wineoss: Use dedicated macros to call interface functions.
[wine.git] / libs / xml2 / xmlIO.c
blob16c29f57a443800a978e3c5da85a325ef4a433f4
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 #include <stdlib.h>
16 #include <errno.h>
18 #ifdef HAVE_SYS_TYPES_H
19 #include <sys/types.h>
20 #endif
21 #ifdef HAVE_SYS_STAT_H
22 #include <sys/stat.h>
23 #endif
24 #ifdef HAVE_FCNTL_H
25 #include <fcntl.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #ifdef LIBXML_ZLIB_ENABLED
31 #include <zlib.h>
32 #endif
33 #ifdef LIBXML_LZMA_ENABLED
34 #include <lzma.h>
35 #endif
37 #if defined(_WIN32)
38 #define WIN32_LEAN_AND_MEAN
39 #include <windows.h>
40 #include <io.h>
41 #include <direct.h>
42 #endif
44 #ifndef S_ISDIR
45 # ifdef _S_ISDIR
46 # define S_ISDIR(x) _S_ISDIR(x)
47 # elif defined(S_IFDIR)
48 # ifdef S_IFMT
49 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
50 # elif defined(_S_IFMT)
51 # define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
52 # endif
53 # endif
54 #endif
56 #include <libxml/xmlmemory.h>
57 #include <libxml/parser.h>
58 #include <libxml/parserInternals.h>
59 #include <libxml/xmlIO.h>
60 #include <libxml/uri.h>
61 #include <libxml/nanohttp.h>
62 #include <libxml/nanoftp.h>
63 #include <libxml/xmlerror.h>
64 #ifdef LIBXML_CATALOG_ENABLED
65 #include <libxml/catalog.h>
66 #endif
67 #include <libxml/globals.h>
69 #include "buf.h"
70 #include "enc.h"
72 /* #define VERBOSE_FAILURE */
73 /* #define DEBUG_EXTERNAL_ENTITIES */
74 /* #define DEBUG_INPUT */
76 #ifdef DEBUG_INPUT
77 #define MINLEN 40
78 #else
79 #define MINLEN 4000
80 #endif
83 * Input I/O callback sets
85 typedef struct _xmlInputCallback {
86 xmlInputMatchCallback matchcallback;
87 xmlInputOpenCallback opencallback;
88 xmlInputReadCallback readcallback;
89 xmlInputCloseCallback closecallback;
90 } xmlInputCallback;
92 #define MAX_INPUT_CALLBACK 15
94 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
95 static int xmlInputCallbackNr = 0;
96 static int xmlInputCallbackInitialized = 0;
98 #ifdef LIBXML_OUTPUT_ENABLED
100 * Output I/O callback sets
102 typedef struct _xmlOutputCallback {
103 xmlOutputMatchCallback matchcallback;
104 xmlOutputOpenCallback opencallback;
105 xmlOutputWriteCallback writecallback;
106 xmlOutputCloseCallback closecallback;
107 } xmlOutputCallback;
109 #define MAX_OUTPUT_CALLBACK 15
111 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
112 static int xmlOutputCallbackNr = 0;
113 static int xmlOutputCallbackInitialized = 0;
115 xmlOutputBufferPtr
116 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
117 #endif /* LIBXML_OUTPUT_ENABLED */
119 /************************************************************************
121 * Tree memory error handler *
123 ************************************************************************/
125 static const char* const IOerr[] = {
126 "Unknown IO error", /* UNKNOWN */
127 "Permission denied", /* EACCES */
128 "Resource temporarily unavailable",/* EAGAIN */
129 "Bad file descriptor", /* EBADF */
130 "Bad message", /* EBADMSG */
131 "Resource busy", /* EBUSY */
132 "Operation canceled", /* ECANCELED */
133 "No child processes", /* ECHILD */
134 "Resource deadlock avoided",/* EDEADLK */
135 "Domain error", /* EDOM */
136 "File exists", /* EEXIST */
137 "Bad address", /* EFAULT */
138 "File too large", /* EFBIG */
139 "Operation in progress", /* EINPROGRESS */
140 "Interrupted function call",/* EINTR */
141 "Invalid argument", /* EINVAL */
142 "Input/output error", /* EIO */
143 "Is a directory", /* EISDIR */
144 "Too many open files", /* EMFILE */
145 "Too many links", /* EMLINK */
146 "Inappropriate message buffer length",/* EMSGSIZE */
147 "Filename too long", /* ENAMETOOLONG */
148 "Too many open files in system",/* ENFILE */
149 "No such device", /* ENODEV */
150 "No such file or directory",/* ENOENT */
151 "Exec format error", /* ENOEXEC */
152 "No locks available", /* ENOLCK */
153 "Not enough space", /* ENOMEM */
154 "No space left on device", /* ENOSPC */
155 "Function not implemented", /* ENOSYS */
156 "Not a directory", /* ENOTDIR */
157 "Directory not empty", /* ENOTEMPTY */
158 "Not supported", /* ENOTSUP */
159 "Inappropriate I/O control operation",/* ENOTTY */
160 "No such device or address",/* ENXIO */
161 "Operation not permitted", /* EPERM */
162 "Broken pipe", /* EPIPE */
163 "Result too large", /* ERANGE */
164 "Read-only file system", /* EROFS */
165 "Invalid seek", /* ESPIPE */
166 "No such process", /* ESRCH */
167 "Operation timed out", /* ETIMEDOUT */
168 "Improper link", /* EXDEV */
169 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
170 "encoder error", /* XML_IO_ENCODER */
171 "flush error",
172 "write error",
173 "no input",
174 "buffer full",
175 "loading error",
176 "not a socket", /* ENOTSOCK */
177 "already connected", /* EISCONN */
178 "connection refused", /* ECONNREFUSED */
179 "unreachable network", /* ENETUNREACH */
180 "address in use", /* EADDRINUSE */
181 "already in use", /* EALREADY */
182 "unknown address family", /* EAFNOSUPPORT */
185 #if defined(_WIN32)
187 * __xmlIOWin32UTF8ToWChar:
188 * @u8String: uft-8 string
190 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
192 static wchar_t *
193 __xmlIOWin32UTF8ToWChar(const char *u8String)
195 wchar_t *wString = NULL;
197 if (u8String) {
198 int wLen =
199 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
200 -1, NULL, 0);
201 if (wLen) {
202 wString = xmlMalloc(wLen * sizeof(wchar_t));
203 if (wString) {
204 if (MultiByteToWideChar
205 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
206 xmlFree(wString);
207 wString = NULL;
213 return wString;
215 #endif
218 * xmlIOErrMemory:
219 * @extra: extra information
221 * Handle an out of memory condition
223 static void
224 xmlIOErrMemory(const char *extra)
226 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
230 * __xmlIOErr:
231 * @code: the error number
233 * @extra: extra information
235 * Handle an I/O error
237 void
238 __xmlIOErr(int domain, int code, const char *extra)
240 unsigned int idx;
242 if (code == 0) {
243 if (errno == 0) code = 0;
244 #ifdef EACCES
245 else if (errno == EACCES) code = XML_IO_EACCES;
246 #endif
247 #ifdef EAGAIN
248 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
249 #endif
250 #ifdef EBADF
251 else if (errno == EBADF) code = XML_IO_EBADF;
252 #endif
253 #ifdef EBADMSG
254 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
255 #endif
256 #ifdef EBUSY
257 else if (errno == EBUSY) code = XML_IO_EBUSY;
258 #endif
259 #ifdef ECANCELED
260 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
261 #endif
262 #ifdef ECHILD
263 else if (errno == ECHILD) code = XML_IO_ECHILD;
264 #endif
265 #ifdef EDEADLK
266 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
267 #endif
268 #ifdef EDOM
269 else if (errno == EDOM) code = XML_IO_EDOM;
270 #endif
271 #ifdef EEXIST
272 else if (errno == EEXIST) code = XML_IO_EEXIST;
273 #endif
274 #ifdef EFAULT
275 else if (errno == EFAULT) code = XML_IO_EFAULT;
276 #endif
277 #ifdef EFBIG
278 else if (errno == EFBIG) code = XML_IO_EFBIG;
279 #endif
280 #ifdef EINPROGRESS
281 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
282 #endif
283 #ifdef EINTR
284 else if (errno == EINTR) code = XML_IO_EINTR;
285 #endif
286 #ifdef EINVAL
287 else if (errno == EINVAL) code = XML_IO_EINVAL;
288 #endif
289 #ifdef EIO
290 else if (errno == EIO) code = XML_IO_EIO;
291 #endif
292 #ifdef EISDIR
293 else if (errno == EISDIR) code = XML_IO_EISDIR;
294 #endif
295 #ifdef EMFILE
296 else if (errno == EMFILE) code = XML_IO_EMFILE;
297 #endif
298 #ifdef EMLINK
299 else if (errno == EMLINK) code = XML_IO_EMLINK;
300 #endif
301 #ifdef EMSGSIZE
302 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
303 #endif
304 #ifdef ENAMETOOLONG
305 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
306 #endif
307 #ifdef ENFILE
308 else if (errno == ENFILE) code = XML_IO_ENFILE;
309 #endif
310 #ifdef ENODEV
311 else if (errno == ENODEV) code = XML_IO_ENODEV;
312 #endif
313 #ifdef ENOENT
314 else if (errno == ENOENT) code = XML_IO_ENOENT;
315 #endif
316 #ifdef ENOEXEC
317 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
318 #endif
319 #ifdef ENOLCK
320 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
321 #endif
322 #ifdef ENOMEM
323 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
324 #endif
325 #ifdef ENOSPC
326 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
327 #endif
328 #ifdef ENOSYS
329 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
330 #endif
331 #ifdef ENOTDIR
332 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
333 #endif
334 #ifdef ENOTEMPTY
335 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
336 #endif
337 #ifdef ENOTSUP
338 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
339 #endif
340 #ifdef ENOTTY
341 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
342 #endif
343 #ifdef ENXIO
344 else if (errno == ENXIO) code = XML_IO_ENXIO;
345 #endif
346 #ifdef EPERM
347 else if (errno == EPERM) code = XML_IO_EPERM;
348 #endif
349 #ifdef EPIPE
350 else if (errno == EPIPE) code = XML_IO_EPIPE;
351 #endif
352 #ifdef ERANGE
353 else if (errno == ERANGE) code = XML_IO_ERANGE;
354 #endif
355 #ifdef EROFS
356 else if (errno == EROFS) code = XML_IO_EROFS;
357 #endif
358 #ifdef ESPIPE
359 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
360 #endif
361 #ifdef ESRCH
362 else if (errno == ESRCH) code = XML_IO_ESRCH;
363 #endif
364 #ifdef ETIMEDOUT
365 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
366 #endif
367 #ifdef EXDEV
368 else if (errno == EXDEV) code = XML_IO_EXDEV;
369 #endif
370 #ifdef ENOTSOCK
371 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
372 #endif
373 #ifdef EISCONN
374 else if (errno == EISCONN) code = XML_IO_EISCONN;
375 #endif
376 #ifdef ECONNREFUSED
377 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
378 #endif
379 #ifdef ETIMEDOUT
380 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
381 #endif
382 #ifdef ENETUNREACH
383 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
384 #endif
385 #ifdef EADDRINUSE
386 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
387 #endif
388 #ifdef EINPROGRESS
389 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
390 #endif
391 #ifdef EALREADY
392 else if (errno == EALREADY) code = XML_IO_EALREADY;
393 #endif
394 #ifdef EAFNOSUPPORT
395 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
396 #endif
397 else code = XML_IO_UNKNOWN;
399 idx = 0;
400 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
401 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
403 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
407 * xmlIOErr:
408 * @code: the error number
409 * @extra: extra information
411 * Handle an I/O error
413 static void
414 xmlIOErr(int code, const char *extra)
416 __xmlIOErr(XML_FROM_IO, code, extra);
420 * __xmlLoaderErr:
421 * @ctx: the parser context
422 * @extra: extra information
424 * Handle a resource access error
426 void
427 __xmlLoaderErr(void *ctx, const char *msg, const char *filename)
429 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
430 xmlStructuredErrorFunc schannel = NULL;
431 xmlGenericErrorFunc channel = NULL;
432 void *data = NULL;
433 xmlErrorLevel level = XML_ERR_ERROR;
435 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
436 (ctxt->instate == XML_PARSER_EOF))
437 return;
438 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
439 if (ctxt->validate) {
440 channel = ctxt->sax->error;
441 level = XML_ERR_ERROR;
442 } else {
443 channel = ctxt->sax->warning;
444 level = XML_ERR_WARNING;
446 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
447 schannel = ctxt->sax->serror;
448 data = ctxt->userData;
450 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
451 XML_IO_LOAD_ERROR, level, NULL, 0,
452 filename, NULL, NULL, 0, 0,
453 msg, filename);
457 /************************************************************************
459 * Tree memory error handler *
461 ************************************************************************/
463 * xmlNormalizeWindowsPath:
464 * @path: the input file path
466 * This function is obsolete. Please see xmlURIFromPath in uri.c for
467 * a better solution.
469 * Returns a canonicalized version of the path
471 xmlChar *
472 xmlNormalizeWindowsPath(const xmlChar *path)
474 return xmlCanonicPath(path);
478 * xmlCleanupInputCallbacks:
480 * clears the entire input callback table. this includes the
481 * compiled-in I/O.
483 void
484 xmlCleanupInputCallbacks(void)
486 int i;
488 if (!xmlInputCallbackInitialized)
489 return;
491 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
492 xmlInputCallbackTable[i].matchcallback = NULL;
493 xmlInputCallbackTable[i].opencallback = NULL;
494 xmlInputCallbackTable[i].readcallback = NULL;
495 xmlInputCallbackTable[i].closecallback = NULL;
498 xmlInputCallbackNr = 0;
499 xmlInputCallbackInitialized = 0;
503 * xmlPopInputCallbacks:
505 * Clear the top input callback from the input stack. this includes the
506 * compiled-in I/O.
508 * Returns the number of input callback registered or -1 in case of error.
511 xmlPopInputCallbacks(void)
513 if (!xmlInputCallbackInitialized)
514 return(-1);
516 if (xmlInputCallbackNr <= 0)
517 return(-1);
519 xmlInputCallbackNr--;
520 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
521 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
522 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
523 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
525 return(xmlInputCallbackNr);
528 #ifdef LIBXML_OUTPUT_ENABLED
530 * xmlCleanupOutputCallbacks:
532 * clears the entire output callback table. this includes the
533 * compiled-in I/O callbacks.
535 void
536 xmlCleanupOutputCallbacks(void)
538 int i;
540 if (!xmlOutputCallbackInitialized)
541 return;
543 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
544 xmlOutputCallbackTable[i].matchcallback = NULL;
545 xmlOutputCallbackTable[i].opencallback = NULL;
546 xmlOutputCallbackTable[i].writecallback = NULL;
547 xmlOutputCallbackTable[i].closecallback = NULL;
550 xmlOutputCallbackNr = 0;
551 xmlOutputCallbackInitialized = 0;
555 * xmlPopOutputCallbacks:
557 * Remove the top output callbacks from the output stack. This includes the
558 * compiled-in I/O.
560 * Returns the number of output callback registered or -1 in case of error.
563 xmlPopOutputCallbacks(void)
565 if (!xmlOutputCallbackInitialized)
566 return(-1);
568 if (xmlOutputCallbackNr <= 0)
569 return(-1);
571 xmlOutputCallbackNr--;
572 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = NULL;
573 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = NULL;
574 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = NULL;
575 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = NULL;
577 return(xmlOutputCallbackNr);
580 #endif /* LIBXML_OUTPUT_ENABLED */
582 /************************************************************************
584 * Standard I/O for file accesses *
586 ************************************************************************/
588 #if defined(_WIN32)
591 * xmlWrapOpenUtf8:
592 * @path: the path in utf-8 encoding
593 * @mode: type of access (0 - read, 1 - write)
595 * function opens the file specified by @path
598 static FILE*
599 xmlWrapOpenUtf8(const char *path,int mode)
601 FILE *fd = NULL;
602 wchar_t *wPath;
604 wPath = __xmlIOWin32UTF8ToWChar(path);
605 if(wPath)
607 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
608 xmlFree(wPath);
610 /* maybe path in native encoding */
611 if(fd == NULL)
612 fd = fopen(path, mode ? "wb" : "rb");
614 return fd;
617 #ifdef LIBXML_ZLIB_ENABLED
618 static gzFile
619 xmlWrapGzOpenUtf8(const char *path, const char *mode)
621 gzFile fd;
622 wchar_t *wPath;
624 fd = gzopen (path, mode);
625 if (fd)
626 return fd;
628 wPath = __xmlIOWin32UTF8ToWChar(path);
629 if(wPath)
631 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
632 #ifdef _O_BINARY
633 m |= (strstr(mode, "b") ? _O_BINARY : 0);
634 #endif
635 d = _wopen(wPath, m);
636 if (d >= 0)
637 fd = gzdopen(d, mode);
638 xmlFree(wPath);
641 return fd;
643 #endif
646 * xmlWrapStatUtf8:
647 * @path: the path in utf-8 encoding
648 * @info: structure that stores results
650 * function obtains information about the file or directory
653 static int
654 xmlWrapStatUtf8(const char *path, struct _stat *info) {
655 int retval = -1;
656 wchar_t *wPath;
658 wPath = __xmlIOWin32UTF8ToWChar(path);
659 if (wPath) {
660 retval = _wstat(wPath, info);
661 xmlFree(wPath);
663 /* maybe path in native encoding */
664 if(retval < 0)
665 retval = _stat(path, info);
666 return retval;
669 #endif
672 * xmlCheckFilename:
673 * @path: the path to check
675 * function checks to see if @path is a valid source
676 * (file, socket...) for XML.
678 * if stat is not available on the target machine,
679 * returns 1. if stat fails, returns 0 (if calling
680 * stat on the filename fails, it can't be right).
681 * if stat succeeds and the file is a directory,
682 * returns 2. otherwise returns 1.
686 xmlCheckFilename (const char *path)
688 #ifdef HAVE_STAT
689 #if defined(_WIN32)
690 struct _stat stat_buffer;
691 #else
692 struct stat stat_buffer;
693 #endif
694 #endif
695 if (path == NULL)
696 return(0);
698 #ifdef HAVE_STAT
699 #if defined(_WIN32)
701 * On Windows stat and wstat do not work with long pathname,
702 * which start with '\\?\'
704 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
705 (path[3] == '\\') )
706 return 1;
708 if (xmlWrapStatUtf8(path, &stat_buffer) == -1)
709 return 0;
710 #else
711 if (stat(path, &stat_buffer) == -1)
712 return 0;
713 #endif
714 #ifdef S_ISDIR
715 if (S_ISDIR(stat_buffer.st_mode))
716 return 2;
717 #endif
718 #endif /* HAVE_STAT */
719 return 1;
723 * xmlInputReadCallbackNop:
725 * No Operation xmlInputReadCallback function, does nothing.
727 * Returns zero
730 xmlInputReadCallbackNop(void *context ATTRIBUTE_UNUSED,
731 char *buffer ATTRIBUTE_UNUSED,
732 int len ATTRIBUTE_UNUSED) {
733 return(0);
737 * xmlFdRead:
738 * @context: the I/O context
739 * @buffer: where to drop data
740 * @len: number of bytes to read
742 * Read @len bytes to @buffer from the I/O channel.
744 * Returns the number of bytes written
746 static int
747 xmlFdRead (void * context, char * buffer, int len) {
748 int ret;
750 ret = read((int) (ptrdiff_t) context, &buffer[0], len);
751 if (ret < 0) xmlIOErr(0, "read()");
752 return(ret);
755 #ifdef LIBXML_OUTPUT_ENABLED
757 * xmlFdWrite:
758 * @context: the I/O context
759 * @buffer: where to get data
760 * @len: number of bytes to write
762 * Write @len bytes from @buffer to the I/O channel.
764 * Returns the number of bytes written
766 static int
767 xmlFdWrite (void * context, const char * buffer, int len) {
768 int ret = 0;
770 if (len > 0) {
771 ret = write((int) (ptrdiff_t) context, &buffer[0], len);
772 if (ret < 0) xmlIOErr(0, "write()");
774 return(ret);
776 #endif /* LIBXML_OUTPUT_ENABLED */
779 * xmlFdClose:
780 * @context: the I/O context
782 * Close an I/O channel
784 * Returns 0 in case of success and error code otherwise
786 static int
787 xmlFdClose (void * context) {
788 int ret;
789 ret = close((int) (ptrdiff_t) context);
790 if (ret < 0) xmlIOErr(0, "close()");
791 return(ret);
795 * xmlFileMatch:
796 * @filename: the URI for matching
798 * input from FILE *
800 * Returns 1 if matches, 0 otherwise
803 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
804 return(1);
808 * xmlFileOpen_real:
809 * @filename: the URI for matching
811 * input from FILE *, supports compressed input
812 * if @filename is " " then the standard input is used
814 * Returns an I/O context or NULL in case of error
816 static void *
817 xmlFileOpen_real (const char *filename) {
818 const char *path = filename;
819 FILE *fd;
821 if (filename == NULL)
822 return(NULL);
824 if (!strcmp(filename, "-")) {
825 fd = stdin;
826 return((void *) fd);
829 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
830 #if defined (_WIN32)
831 path = &filename[17];
832 #else
833 path = &filename[16];
834 #endif
835 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
836 #if defined (_WIN32)
837 path = &filename[8];
838 #else
839 path = &filename[7];
840 #endif
841 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
842 /* lots of generators seems to lazy to read RFC 1738 */
843 #if defined (_WIN32)
844 path = &filename[6];
845 #else
846 path = &filename[5];
847 #endif
850 /* Do not check DDNAME on zOS ! */
851 #if !defined(__MVS__)
852 if (!xmlCheckFilename(path))
853 return(NULL);
854 #endif
856 #if defined(_WIN32)
857 fd = xmlWrapOpenUtf8(path, 0);
858 #else
859 fd = fopen(path, "rb");
860 #endif /* WIN32 */
861 if (fd == NULL) xmlIOErr(0, path);
862 return((void *) fd);
866 * xmlFileOpen:
867 * @filename: the URI for matching
869 * Wrapper around xmlFileOpen_real that try it with an unescaped
870 * version of @filename, if this fails fallback to @filename
872 * Returns a handler or NULL in case or failure
874 void *
875 xmlFileOpen (const char *filename) {
876 char *unescaped;
877 void *retval;
879 retval = xmlFileOpen_real(filename);
880 if (retval == NULL) {
881 unescaped = xmlURIUnescapeString(filename, 0, NULL);
882 if (unescaped != NULL) {
883 retval = xmlFileOpen_real(unescaped);
884 xmlFree(unescaped);
888 return retval;
891 #ifdef LIBXML_OUTPUT_ENABLED
893 * xmlFileOpenW:
894 * @filename: the URI for matching
896 * output to from FILE *,
897 * if @filename is "-" then the standard output is used
899 * Returns an I/O context or NULL in case of error
901 static void *
902 xmlFileOpenW (const char *filename) {
903 const char *path = NULL;
904 FILE *fd;
906 if (!strcmp(filename, "-")) {
907 fd = stdout;
908 return((void *) fd);
911 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
912 #if defined (_WIN32)
913 path = &filename[17];
914 #else
915 path = &filename[16];
916 #endif
917 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
918 #if defined (_WIN32)
919 path = &filename[8];
920 #else
921 path = &filename[7];
922 #endif
923 } else
924 path = filename;
926 if (path == NULL)
927 return(NULL);
929 #if defined(_WIN32)
930 fd = xmlWrapOpenUtf8(path, 1);
931 #elif(__MVS__)
932 fd = fopen(path, "w");
933 #else
934 fd = fopen(path, "wb");
935 #endif /* WIN32 */
937 if (fd == NULL) xmlIOErr(0, path);
938 return((void *) fd);
940 #endif /* LIBXML_OUTPUT_ENABLED */
943 * xmlFileRead:
944 * @context: the I/O context
945 * @buffer: where to drop data
946 * @len: number of bytes to write
948 * Read @len bytes to @buffer from the I/O channel.
950 * Returns the number of bytes written or < 0 in case of failure
953 xmlFileRead (void * context, char * buffer, int len) {
954 int ret;
955 if ((context == NULL) || (buffer == NULL))
956 return(-1);
957 ret = fread(&buffer[0], 1, len, (FILE *) context);
958 if (ret < 0) xmlIOErr(0, "fread()");
959 return(ret);
962 #ifdef LIBXML_OUTPUT_ENABLED
964 * xmlFileWrite:
965 * @context: the I/O context
966 * @buffer: where to drop data
967 * @len: number of bytes to write
969 * Write @len bytes from @buffer to the I/O channel.
971 * Returns the number of bytes written
973 static int
974 xmlFileWrite (void * context, const char * buffer, int len) {
975 int items;
977 if ((context == NULL) || (buffer == NULL))
978 return(-1);
979 items = fwrite(&buffer[0], len, 1, (FILE *) context);
980 if ((items == 0) && (ferror((FILE *) context))) {
981 xmlIOErr(0, "fwrite()");
982 return(-1);
984 return(items * len);
986 #endif /* LIBXML_OUTPUT_ENABLED */
989 * xmlFileClose:
990 * @context: the I/O context
992 * Close an I/O channel
994 * Returns 0 or -1 in case of error
997 xmlFileClose (void * context) {
998 FILE *fil;
999 int ret;
1001 if (context == NULL)
1002 return(-1);
1003 fil = (FILE *) context;
1004 if ((fil == stdout) || (fil == stderr)) {
1005 ret = fflush(fil);
1006 if (ret < 0)
1007 xmlIOErr(0, "fflush()");
1008 return(0);
1010 if (fil == stdin)
1011 return(0);
1012 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1013 if (ret < 0)
1014 xmlIOErr(0, "fclose()");
1015 return(ret);
1019 * xmlFileFlush:
1020 * @context: the I/O context
1022 * Flush an I/O channel
1024 static int
1025 xmlFileFlush (void * context) {
1026 int ret;
1028 if (context == NULL)
1029 return(-1);
1030 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1031 if (ret < 0)
1032 xmlIOErr(0, "fflush()");
1033 return(ret);
1036 #ifdef LIBXML_OUTPUT_ENABLED
1038 * xmlBufferWrite:
1039 * @context: the xmlBuffer
1040 * @buffer: the data to write
1041 * @len: number of bytes to write
1043 * Write @len bytes from @buffer to the xml buffer
1045 * Returns the number of bytes written
1047 static int
1048 xmlBufferWrite (void * context, const char * buffer, int len) {
1049 int ret;
1051 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1052 if (ret != 0)
1053 return(-1);
1054 return(len);
1056 #endif
1058 #ifdef LIBXML_ZLIB_ENABLED
1059 /************************************************************************
1061 * I/O for compressed file accesses *
1063 ************************************************************************/
1065 * xmlGzfileMatch:
1066 * @filename: the URI for matching
1068 * input from compressed file test
1070 * Returns 1 if matches, 0 otherwise
1072 static int
1073 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1074 return(1);
1078 * xmlGzfileOpen_real:
1079 * @filename: the URI for matching
1081 * input from compressed file open
1082 * if @filename is " " then the standard input is used
1084 * Returns an I/O context or NULL in case of error
1086 static void *
1087 xmlGzfileOpen_real (const char *filename) {
1088 const char *path = NULL;
1089 gzFile fd;
1091 if (!strcmp(filename, "-")) {
1092 int duped_fd = dup(fileno(stdin));
1093 fd = gzdopen(duped_fd, "rb");
1094 if (fd == Z_NULL && duped_fd >= 0) {
1095 close(duped_fd); /* gzdOpen() does not close on failure */
1098 return((void *) fd);
1101 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
1102 #if defined (_WIN32)
1103 path = &filename[17];
1104 #else
1105 path = &filename[16];
1106 #endif
1107 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1108 #if defined (_WIN32)
1109 path = &filename[8];
1110 #else
1111 path = &filename[7];
1112 #endif
1113 } else
1114 path = filename;
1116 if (path == NULL)
1117 return(NULL);
1118 if (!xmlCheckFilename(path))
1119 return(NULL);
1121 #if defined(_WIN32)
1122 fd = xmlWrapGzOpenUtf8(path, "rb");
1123 #else
1124 fd = gzopen(path, "rb");
1125 #endif
1126 return((void *) fd);
1130 * xmlGzfileOpen:
1131 * @filename: the URI for matching
1133 * Wrapper around xmlGzfileOpen_real if the open fails, it will
1134 * try to unescape @filename
1136 static void *
1137 xmlGzfileOpen (const char *filename) {
1138 char *unescaped;
1139 void *retval;
1141 retval = xmlGzfileOpen_real(filename);
1142 if (retval == NULL) {
1143 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1144 if (unescaped != NULL) {
1145 retval = xmlGzfileOpen_real(unescaped);
1147 xmlFree(unescaped);
1149 return retval;
1152 #ifdef LIBXML_OUTPUT_ENABLED
1154 * xmlGzfileOpenW:
1155 * @filename: the URI for matching
1156 * @compression: the compression factor (0 - 9 included)
1158 * input from compressed file open
1159 * if @filename is " " then the standard input is used
1161 * Returns an I/O context or NULL in case of error
1163 static void *
1164 xmlGzfileOpenW (const char *filename, int compression) {
1165 const char *path = NULL;
1166 char mode[15];
1167 gzFile fd;
1169 snprintf(mode, sizeof(mode), "wb%d", compression);
1170 if (!strcmp(filename, "-")) {
1171 int duped_fd = dup(fileno(stdout));
1172 fd = gzdopen(duped_fd, "rb");
1173 if (fd == Z_NULL && duped_fd >= 0) {
1174 close(duped_fd); /* gzdOpen() does not close on failure */
1177 return((void *) fd);
1180 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
1181 #if defined (_WIN32)
1182 path = &filename[17];
1183 #else
1184 path = &filename[16];
1185 #endif
1186 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1187 #if defined (_WIN32)
1188 path = &filename[8];
1189 #else
1190 path = &filename[7];
1191 #endif
1192 } else
1193 path = filename;
1195 if (path == NULL)
1196 return(NULL);
1198 #if defined(_WIN32)
1199 fd = xmlWrapGzOpenUtf8(path, mode);
1200 #else
1201 fd = gzopen(path, mode);
1202 #endif
1203 return((void *) fd);
1205 #endif /* LIBXML_OUTPUT_ENABLED */
1208 * xmlGzfileRead:
1209 * @context: the I/O context
1210 * @buffer: where to drop data
1211 * @len: number of bytes to write
1213 * Read @len bytes to @buffer from the compressed I/O channel.
1215 * Returns the number of bytes read.
1217 static int
1218 xmlGzfileRead (void * context, char * buffer, int len) {
1219 int ret;
1221 ret = gzread((gzFile) context, &buffer[0], len);
1222 if (ret < 0) xmlIOErr(0, "gzread()");
1223 return(ret);
1226 #ifdef LIBXML_OUTPUT_ENABLED
1228 * xmlGzfileWrite:
1229 * @context: the I/O context
1230 * @buffer: where to drop data
1231 * @len: number of bytes to write
1233 * Write @len bytes from @buffer to the compressed I/O channel.
1235 * Returns the number of bytes written
1237 static int
1238 xmlGzfileWrite (void * context, const char * buffer, int len) {
1239 int ret;
1241 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1242 if (ret < 0) xmlIOErr(0, "gzwrite()");
1243 return(ret);
1245 #endif /* LIBXML_OUTPUT_ENABLED */
1248 * xmlGzfileClose:
1249 * @context: the I/O context
1251 * Close a compressed I/O channel
1253 static int
1254 xmlGzfileClose (void * context) {
1255 int ret;
1257 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1258 if (ret < 0) xmlIOErr(0, "gzclose()");
1259 return(ret);
1261 #endif /* LIBXML_ZLIB_ENABLED */
1263 #ifdef LIBXML_LZMA_ENABLED
1264 /************************************************************************
1266 * I/O for compressed file accesses *
1268 ************************************************************************/
1269 #include "xzlib.h"
1271 * xmlXzfileMatch:
1272 * @filename: the URI for matching
1274 * input from compressed file test
1276 * Returns 1 if matches, 0 otherwise
1278 static int
1279 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1280 return(1);
1284 * xmlXzFileOpen_real:
1285 * @filename: the URI for matching
1287 * input from compressed file open
1288 * if @filename is " " then the standard input is used
1290 * Returns an I/O context or NULL in case of error
1292 static void *
1293 xmlXzfileOpen_real (const char *filename) {
1294 const char *path = NULL;
1295 xzFile fd;
1297 if (!strcmp(filename, "-")) {
1298 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
1299 return((void *) fd);
1302 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1303 path = &filename[16];
1304 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1305 path = &filename[7];
1306 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1307 /* lots of generators seems to lazy to read RFC 1738 */
1308 path = &filename[5];
1309 } else
1310 path = filename;
1312 if (path == NULL)
1313 return(NULL);
1314 if (!xmlCheckFilename(path))
1315 return(NULL);
1317 fd = __libxml2_xzopen(path, "rb");
1318 return((void *) fd);
1322 * xmlXzfileOpen:
1323 * @filename: the URI for matching
1325 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1326 * version of @filename, if this fails fallback to @filename
1328 * Returns a handler or NULL in case or failure
1330 static void *
1331 xmlXzfileOpen (const char *filename) {
1332 char *unescaped;
1333 void *retval;
1335 retval = xmlXzfileOpen_real(filename);
1336 if (retval == NULL) {
1337 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1338 if (unescaped != NULL) {
1339 retval = xmlXzfileOpen_real(unescaped);
1341 xmlFree(unescaped);
1344 return retval;
1348 * xmlXzfileRead:
1349 * @context: the I/O context
1350 * @buffer: where to drop data
1351 * @len: number of bytes to write
1353 * Read @len bytes to @buffer from the compressed I/O channel.
1355 * Returns the number of bytes written
1357 static int
1358 xmlXzfileRead (void * context, char * buffer, int len) {
1359 int ret;
1361 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
1362 if (ret < 0) xmlIOErr(0, "xzread()");
1363 return(ret);
1367 * xmlXzfileClose:
1368 * @context: the I/O context
1370 * Close a compressed I/O channel
1372 static int
1373 xmlXzfileClose (void * context) {
1374 int ret;
1376 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
1377 if (ret < 0) xmlIOErr(0, "xzclose()");
1378 return(ret);
1380 #endif /* LIBXML_LZMA_ENABLED */
1382 #ifdef LIBXML_HTTP_ENABLED
1383 /************************************************************************
1385 * I/O for HTTP file accesses *
1387 ************************************************************************/
1389 #ifdef LIBXML_OUTPUT_ENABLED
1390 typedef struct xmlIOHTTPWriteCtxt_
1392 int compression;
1394 char * uri;
1396 void * doc_buff;
1398 } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1400 #ifdef LIBXML_ZLIB_ENABLED
1402 #define DFLT_WBITS ( -15 )
1403 #define DFLT_MEM_LVL ( 8 )
1404 #define GZ_MAGIC1 ( 0x1f )
1405 #define GZ_MAGIC2 ( 0x8b )
1406 #define LXML_ZLIB_OS_CODE ( 0x03 )
1407 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1408 #define DFLT_ZLIB_RATIO ( 5 )
1411 ** Data structure and functions to work with sending compressed data
1412 ** via HTTP.
1415 typedef struct xmlZMemBuff_
1417 unsigned long size;
1418 unsigned long crc;
1420 unsigned char * zbuff;
1421 z_stream zctrl;
1423 } xmlZMemBuff, *xmlZMemBuffPtr;
1426 * append_reverse_ulong
1427 * @buff: Compressed memory buffer
1428 * @data: Unsigned long to append
1430 * Append a unsigned long in reverse byte order to the end of the
1431 * memory buffer.
1433 static void
1434 append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1436 int idx;
1438 if ( buff == NULL )
1439 return;
1442 ** This is plagiarized from putLong in gzio.c (zlib source) where
1443 ** the number "4" is hardcoded. If zlib is ever patched to
1444 ** support 64 bit file sizes, this code would need to be patched
1445 ** as well.
1448 for ( idx = 0; idx < 4; idx++ ) {
1449 *buff->zctrl.next_out = ( data & 0xff );
1450 data >>= 8;
1451 buff->zctrl.next_out++;
1454 return;
1459 * xmlFreeZMemBuff
1460 * @buff: The memory buffer context to clear
1462 * Release all the resources associated with the compressed memory buffer.
1464 static void
1465 xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
1467 #ifdef DEBUG_HTTP
1468 int z_err;
1469 #endif
1471 if ( buff == NULL )
1472 return;
1474 xmlFree( buff->zbuff );
1475 #ifdef DEBUG_HTTP
1476 z_err = deflateEnd( &buff->zctrl );
1477 if ( z_err != Z_OK )
1478 xmlGenericError( xmlGenericErrorContext,
1479 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1480 z_err );
1481 #else
1482 deflateEnd( &buff->zctrl );
1483 #endif
1485 xmlFree( buff );
1486 return;
1490 * xmlCreateZMemBuff
1491 *@compression: Compression value to use
1493 * Create a memory buffer to hold the compressed XML document. The
1494 * compressed document in memory will end up being identical to what
1495 * would be created if gzopen/gzwrite/gzclose were being used to
1496 * write the document to disk. The code for the header/trailer data to
1497 * the compression is plagiarized from the zlib source files.
1499 static void *
1500 xmlCreateZMemBuff( int compression ) {
1502 int z_err;
1503 int hdr_lgth;
1504 xmlZMemBuffPtr buff = NULL;
1506 if ( ( compression < 1 ) || ( compression > 9 ) )
1507 return ( NULL );
1509 /* Create the control and data areas */
1511 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1512 if ( buff == NULL ) {
1513 xmlIOErrMemory("creating buffer context");
1514 return ( NULL );
1517 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1518 buff->size = INIT_HTTP_BUFF_SIZE;
1519 buff->zbuff = xmlMalloc( buff->size );
1520 if ( buff->zbuff == NULL ) {
1521 xmlFreeZMemBuff( buff );
1522 xmlIOErrMemory("creating buffer");
1523 return ( NULL );
1526 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1527 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1528 if ( z_err != Z_OK ) {
1529 xmlChar msg[500];
1530 xmlFreeZMemBuff( buff );
1531 buff = NULL;
1532 xmlStrPrintf(msg, 500,
1533 "xmlCreateZMemBuff: %s %d\n",
1534 "Error initializing compression context. ZLIB error:",
1535 z_err );
1536 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1537 return ( NULL );
1540 /* Set the header data. The CRC will be needed for the trailer */
1541 buff->crc = crc32( 0L, NULL, 0 );
1542 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1543 "%c%c%c%c%c%c%c%c%c%c",
1544 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1545 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1546 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1547 buff->zctrl.avail_out = buff->size - hdr_lgth;
1549 return ( buff );
1553 * xmlZMemBuffExtend
1554 * @buff: Buffer used to compress and consolidate data.
1555 * @ext_amt: Number of bytes to extend the buffer.
1557 * Extend the internal buffer used to store the compressed data by the
1558 * specified amount.
1560 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1561 * the original buffer still exists at the original size.
1563 static int
1564 xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1566 int rc = -1;
1567 size_t new_size;
1568 size_t cur_used;
1570 unsigned char * tmp_ptr = NULL;
1572 if ( buff == NULL )
1573 return ( -1 );
1575 else if ( ext_amt == 0 )
1576 return ( 0 );
1578 cur_used = buff->zctrl.next_out - buff->zbuff;
1579 new_size = buff->size + ext_amt;
1581 #ifdef DEBUG_HTTP
1582 if ( cur_used > new_size )
1583 xmlGenericError( xmlGenericErrorContext,
1584 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1585 "Buffer overwrite detected during compressed memory",
1586 "buffer extension. Overflowed by",
1587 (cur_used - new_size ) );
1588 #endif
1590 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1591 if ( tmp_ptr != NULL ) {
1592 rc = 0;
1593 buff->size = new_size;
1594 buff->zbuff = tmp_ptr;
1595 buff->zctrl.next_out = tmp_ptr + cur_used;
1596 buff->zctrl.avail_out = new_size - cur_used;
1598 else {
1599 xmlChar msg[500];
1600 xmlStrPrintf(msg, 500,
1601 "xmlZMemBuffExtend: %s %lu bytes.\n",
1602 "Allocation failure extending output buffer to",
1603 (unsigned long) new_size );
1604 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1607 return ( rc );
1611 * xmlZMemBuffAppend
1612 * @buff: Buffer used to compress and consolidate data
1613 * @src: Uncompressed source content to append to buffer
1614 * @len: Length of source data to append to buffer
1616 * Compress and append data to the internal buffer. The data buffer
1617 * will be expanded if needed to store the additional data.
1619 * Returns the number of bytes appended to the buffer or -1 on error.
1621 static int
1622 xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1624 int z_err;
1625 size_t min_accept;
1627 if ( ( buff == NULL ) || ( src == NULL ) )
1628 return ( -1 );
1630 buff->zctrl.avail_in = len;
1631 buff->zctrl.next_in = (unsigned char *)src;
1632 while ( buff->zctrl.avail_in > 0 ) {
1634 ** Extend the buffer prior to deflate call if a reasonable amount
1635 ** of output buffer space is not available.
1637 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1638 if ( buff->zctrl.avail_out <= min_accept ) {
1639 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1640 return ( -1 );
1643 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1644 if ( z_err != Z_OK ) {
1645 xmlChar msg[500];
1646 xmlStrPrintf(msg, 500,
1647 "xmlZMemBuffAppend: %s %d %s - %d",
1648 "Compression error while appending",
1649 len, "bytes to buffer. ZLIB error", z_err );
1650 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1651 return ( -1 );
1655 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1657 return ( len );
1661 * xmlZMemBuffGetContent
1662 * @buff: Compressed memory content buffer
1663 * @data_ref: Pointer reference to point to compressed content
1665 * Flushes the compression buffers, appends gzip file trailers and
1666 * returns the compressed content and length of the compressed data.
1667 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1669 * Returns the length of the compressed data or -1 on error.
1671 static int
1672 xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1674 int zlgth = -1;
1675 int z_err;
1677 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1678 return ( -1 );
1680 /* Need to loop until compression output buffers are flushed */
1684 z_err = deflate( &buff->zctrl, Z_FINISH );
1685 if ( z_err == Z_OK ) {
1686 /* In this case Z_OK means more buffer space needed */
1688 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1689 return ( -1 );
1692 while ( z_err == Z_OK );
1694 /* If the compression state is not Z_STREAM_END, some error occurred */
1696 if ( z_err == Z_STREAM_END ) {
1698 /* Need to append the gzip data trailer */
1700 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1701 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1702 return ( -1 );
1706 ** For whatever reason, the CRC and length data are pushed out
1707 ** in reverse byte order. So a memcpy can't be used here.
1710 append_reverse_ulong( buff, buff->crc );
1711 append_reverse_ulong( buff, buff->zctrl.total_in );
1713 zlgth = buff->zctrl.next_out - buff->zbuff;
1714 *data_ref = (char *)buff->zbuff;
1717 else {
1718 xmlChar msg[500];
1719 xmlStrPrintf(msg, 500,
1720 "xmlZMemBuffGetContent: %s - %d\n",
1721 "Error flushing zlib buffers. Error code", z_err );
1722 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1725 return ( zlgth );
1727 #endif /* LIBXML_OUTPUT_ENABLED */
1728 #endif /* LIBXML_ZLIB_ENABLED */
1730 #ifdef LIBXML_OUTPUT_ENABLED
1732 * xmlFreeHTTPWriteCtxt
1733 * @ctxt: Context to cleanup
1735 * Free allocated memory and reclaim system resources.
1737 * No return value.
1739 static void
1740 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1742 if ( ctxt->uri != NULL )
1743 xmlFree( ctxt->uri );
1745 if ( ctxt->doc_buff != NULL ) {
1747 #ifdef LIBXML_ZLIB_ENABLED
1748 if ( ctxt->compression > 0 ) {
1749 xmlFreeZMemBuff( ctxt->doc_buff );
1751 else
1752 #endif
1754 xmlOutputBufferClose( ctxt->doc_buff );
1758 xmlFree( ctxt );
1759 return;
1761 #endif /* LIBXML_OUTPUT_ENABLED */
1765 * xmlIOHTTPMatch:
1766 * @filename: the URI for matching
1768 * check if the URI matches an HTTP one
1770 * Returns 1 if matches, 0 otherwise
1773 xmlIOHTTPMatch (const char *filename) {
1774 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
1775 return(1);
1776 return(0);
1780 * xmlIOHTTPOpen:
1781 * @filename: the URI for matching
1783 * open an HTTP I/O channel
1785 * Returns an I/O context or NULL in case of error
1787 void *
1788 xmlIOHTTPOpen (const char *filename) {
1789 return(xmlNanoHTTPOpen(filename, NULL));
1792 #ifdef LIBXML_OUTPUT_ENABLED
1794 * xmlIOHTTPOpenW:
1795 * @post_uri: The destination URI for the document
1796 * @compression: The compression desired for the document.
1798 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1799 * request. Non-static as is called from the output buffer creation routine.
1801 * Returns an I/O context or NULL in case of error.
1804 void *
1805 xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED)
1808 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
1810 if (post_uri == NULL)
1811 return (NULL);
1813 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1814 if (ctxt == NULL) {
1815 xmlIOErrMemory("creating HTTP output context");
1816 return (NULL);
1819 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
1821 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1822 if (ctxt->uri == NULL) {
1823 xmlIOErrMemory("copying URI");
1824 xmlFreeHTTPWriteCtxt(ctxt);
1825 return (NULL);
1829 * ** Since the document length is required for an HTTP post,
1830 * ** need to put the document into a buffer. A memory buffer
1831 * ** is being used to avoid pushing the data to disk and back.
1834 #ifdef LIBXML_ZLIB_ENABLED
1835 if ((compression > 0) && (compression <= 9)) {
1837 ctxt->compression = compression;
1838 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1839 } else
1840 #endif
1842 /* Any character conversions should have been done before this */
1844 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
1847 if (ctxt->doc_buff == NULL) {
1848 xmlFreeHTTPWriteCtxt(ctxt);
1849 ctxt = NULL;
1852 return (ctxt);
1854 #endif /* LIBXML_OUTPUT_ENABLED */
1856 #ifdef LIBXML_OUTPUT_ENABLED
1858 * xmlIOHTTPDfltOpenW
1859 * @post_uri: The destination URI for this document.
1861 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1862 * HTTP post command. This function should generally not be used as
1863 * the open callback is short circuited in xmlOutputBufferCreateFile.
1865 * Returns a pointer to the new IO context.
1867 static void *
1868 xmlIOHTTPDfltOpenW( const char * post_uri ) {
1869 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1871 #endif /* LIBXML_OUTPUT_ENABLED */
1874 * xmlIOHTTPRead:
1875 * @context: the I/O context
1876 * @buffer: where to drop data
1877 * @len: number of bytes to write
1879 * Read @len bytes to @buffer from the I/O channel.
1881 * Returns the number of bytes written
1884 xmlIOHTTPRead(void * context, char * buffer, int len) {
1885 if ((buffer == NULL) || (len < 0)) return(-1);
1886 return(xmlNanoHTTPRead(context, &buffer[0], len));
1889 #ifdef LIBXML_OUTPUT_ENABLED
1891 * xmlIOHTTPWrite
1892 * @context: previously opened writing context
1893 * @buffer: data to output to temporary buffer
1894 * @len: bytes to output
1896 * Collect data from memory buffer into a temporary file for later
1897 * processing.
1899 * Returns number of bytes written.
1902 static int
1903 xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1905 xmlIOHTTPWriteCtxtPtr ctxt = context;
1907 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1908 return ( -1 );
1910 if ( len > 0 ) {
1912 /* Use gzwrite or fwrite as previously setup in the open call */
1914 #ifdef LIBXML_ZLIB_ENABLED
1915 if ( ctxt->compression > 0 )
1916 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1918 else
1919 #endif
1920 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1922 if ( len < 0 ) {
1923 xmlChar msg[500];
1924 xmlStrPrintf(msg, 500,
1925 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1926 "Error appending to internal buffer.",
1927 "Error sending document to URI",
1928 ctxt->uri );
1929 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1933 return ( len );
1935 #endif /* LIBXML_OUTPUT_ENABLED */
1939 * xmlIOHTTPClose:
1940 * @context: the I/O context
1942 * Close an HTTP I/O channel
1944 * Returns 0
1947 xmlIOHTTPClose (void * context) {
1948 xmlNanoHTTPClose(context);
1949 return 0;
1952 #ifdef LIBXML_OUTPUT_ENABLED
1954 * xmlIOHTTCloseWrite
1955 * @context: The I/O context
1956 * @http_mthd: The HTTP method to be used when sending the data
1958 * Close the transmit HTTP I/O channel and actually send the data.
1960 static int
1961 xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1963 int close_rc = -1;
1964 int http_rtn = 0;
1965 int content_lgth = 0;
1966 xmlIOHTTPWriteCtxtPtr ctxt = context;
1968 char * http_content = NULL;
1969 char * content_encoding = NULL;
1970 char * content_type = (char *) "text/xml";
1971 void * http_ctxt = NULL;
1973 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1974 return ( -1 );
1976 /* Retrieve the content from the appropriate buffer */
1978 #ifdef LIBXML_ZLIB_ENABLED
1980 if ( ctxt->compression > 0 ) {
1981 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1982 content_encoding = (char *) "Content-Encoding: gzip";
1984 else
1985 #endif
1987 /* Pull the data out of the memory output buffer */
1989 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1990 http_content = (char *) xmlBufContent(dctxt->buffer);
1991 content_lgth = xmlBufUse(dctxt->buffer);
1994 if ( http_content == NULL ) {
1995 xmlChar msg[500];
1996 xmlStrPrintf(msg, 500,
1997 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1998 "Error retrieving content.\nUnable to",
1999 http_mthd, "data to URI", ctxt->uri );
2000 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2003 else {
2005 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
2006 &content_type, content_encoding,
2007 content_lgth );
2009 if ( http_ctxt != NULL ) {
2010 #ifdef DEBUG_HTTP
2011 /* If testing/debugging - dump reply with request content */
2013 FILE * tst_file = NULL;
2014 char buffer[ 4096 ];
2015 char * dump_name = NULL;
2016 int avail;
2018 xmlGenericError( xmlGenericErrorContext,
2019 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2020 http_mthd, ctxt->uri,
2021 xmlNanoHTTPReturnCode( http_ctxt ) );
2024 ** Since either content or reply may be gzipped,
2025 ** dump them to separate files instead of the
2026 ** standard error context.
2029 dump_name = tempnam( NULL, "lxml" );
2030 if ( dump_name != NULL ) {
2031 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
2033 tst_file = fopen( buffer, "wb" );
2034 if ( tst_file != NULL ) {
2035 xmlGenericError( xmlGenericErrorContext,
2036 "Transmitted content saved in file: %s\n", buffer );
2038 fwrite( http_content, sizeof( char ),
2039 content_lgth, tst_file );
2040 fclose( tst_file );
2043 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
2044 tst_file = fopen( buffer, "wb" );
2045 if ( tst_file != NULL ) {
2046 xmlGenericError( xmlGenericErrorContext,
2047 "Reply content saved in file: %s\n", buffer );
2050 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2051 buffer, sizeof( buffer ) )) > 0 ) {
2053 fwrite( buffer, sizeof( char ), avail, tst_file );
2056 fclose( tst_file );
2059 free( dump_name );
2061 #endif /* DEBUG_HTTP */
2063 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2064 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2065 close_rc = 0;
2066 else {
2067 xmlChar msg[500];
2068 xmlStrPrintf(msg, 500,
2069 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2070 http_mthd, content_lgth,
2071 "bytes to URI", ctxt->uri,
2072 "failed. HTTP return code:", http_rtn );
2073 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2076 xmlNanoHTTPClose( http_ctxt );
2077 xmlFree( content_type );
2081 /* Final cleanups */
2083 xmlFreeHTTPWriteCtxt( ctxt );
2085 return ( close_rc );
2089 * xmlIOHTTPClosePut
2091 * @context: The I/O context
2093 * Close the transmit HTTP I/O channel and actually send data using a PUT
2094 * HTTP method.
2096 static int
2097 xmlIOHTTPClosePut( void * ctxt ) {
2098 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2103 * xmlIOHTTPClosePost
2105 * @context: The I/O context
2107 * Close the transmit HTTP I/O channel and actually send data using a POST
2108 * HTTP method.
2110 static int
2111 xmlIOHTTPClosePost( void * ctxt ) {
2112 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2114 #endif /* LIBXML_OUTPUT_ENABLED */
2116 #endif /* LIBXML_HTTP_ENABLED */
2118 #ifdef LIBXML_FTP_ENABLED
2119 /************************************************************************
2121 * I/O for FTP file accesses *
2123 ************************************************************************/
2125 * xmlIOFTPMatch:
2126 * @filename: the URI for matching
2128 * check if the URI matches an FTP one
2130 * Returns 1 if matches, 0 otherwise
2133 xmlIOFTPMatch (const char *filename) {
2134 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
2135 return(1);
2136 return(0);
2140 * xmlIOFTPOpen:
2141 * @filename: the URI for matching
2143 * open an FTP I/O channel
2145 * Returns an I/O context or NULL in case of error
2147 void *
2148 xmlIOFTPOpen (const char *filename) {
2149 return(xmlNanoFTPOpen(filename));
2153 * xmlIOFTPRead:
2154 * @context: the I/O context
2155 * @buffer: where to drop data
2156 * @len: number of bytes to write
2158 * Read @len bytes to @buffer from the I/O channel.
2160 * Returns the number of bytes written
2163 xmlIOFTPRead(void * context, char * buffer, int len) {
2164 if ((buffer == NULL) || (len < 0)) return(-1);
2165 return(xmlNanoFTPRead(context, &buffer[0], len));
2169 * xmlIOFTPClose:
2170 * @context: the I/O context
2172 * Close an FTP I/O channel
2174 * Returns 0
2177 xmlIOFTPClose (void * context) {
2178 return ( xmlNanoFTPClose(context) );
2180 #endif /* LIBXML_FTP_ENABLED */
2184 * xmlRegisterInputCallbacks:
2185 * @matchFunc: the xmlInputMatchCallback
2186 * @openFunc: the xmlInputOpenCallback
2187 * @readFunc: the xmlInputReadCallback
2188 * @closeFunc: the xmlInputCloseCallback
2190 * Register a new set of I/O callback for handling parser input.
2192 * Returns the registered handler number or -1 in case of error
2195 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2196 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2197 xmlInputCloseCallback closeFunc) {
2198 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2199 return(-1);
2201 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2202 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2203 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2204 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
2205 xmlInputCallbackInitialized = 1;
2206 return(xmlInputCallbackNr++);
2209 #ifdef LIBXML_OUTPUT_ENABLED
2211 * xmlRegisterOutputCallbacks:
2212 * @matchFunc: the xmlOutputMatchCallback
2213 * @openFunc: the xmlOutputOpenCallback
2214 * @writeFunc: the xmlOutputWriteCallback
2215 * @closeFunc: the xmlOutputCloseCallback
2217 * Register a new set of I/O callback for handling output.
2219 * Returns the registered handler number or -1 in case of error
2222 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2223 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2224 xmlOutputCloseCallback closeFunc) {
2225 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
2226 return(-1);
2228 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2229 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2230 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2231 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
2232 xmlOutputCallbackInitialized = 1;
2233 return(xmlOutputCallbackNr++);
2235 #endif /* LIBXML_OUTPUT_ENABLED */
2238 * xmlRegisterDefaultInputCallbacks:
2240 * Registers the default compiled-in I/O handlers.
2242 void
2243 xmlRegisterDefaultInputCallbacks(void) {
2244 if (xmlInputCallbackInitialized)
2245 return;
2247 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2248 xmlFileRead, xmlFileClose);
2249 #ifdef LIBXML_ZLIB_ENABLED
2250 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2251 xmlGzfileRead, xmlGzfileClose);
2252 #endif /* LIBXML_ZLIB_ENABLED */
2253 #ifdef LIBXML_LZMA_ENABLED
2254 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2255 xmlXzfileRead, xmlXzfileClose);
2256 #endif /* LIBXML_LZMA_ENABLED */
2258 #ifdef LIBXML_HTTP_ENABLED
2259 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2260 xmlIOHTTPRead, xmlIOHTTPClose);
2261 #endif /* LIBXML_HTTP_ENABLED */
2263 #ifdef LIBXML_FTP_ENABLED
2264 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2265 xmlIOFTPRead, xmlIOFTPClose);
2266 #endif /* LIBXML_FTP_ENABLED */
2267 xmlInputCallbackInitialized = 1;
2270 #ifdef LIBXML_OUTPUT_ENABLED
2272 * xmlRegisterDefaultOutputCallbacks:
2274 * Registers the default compiled-in I/O handlers.
2276 void
2277 xmlRegisterDefaultOutputCallbacks (void) {
2278 if (xmlOutputCallbackInitialized)
2279 return;
2281 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2282 xmlFileWrite, xmlFileClose);
2284 #ifdef LIBXML_HTTP_ENABLED
2285 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2286 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2287 #endif
2289 /*********************************
2290 No way a-priori to distinguish between gzipped files from
2291 uncompressed ones except opening if existing then closing
2292 and saving with same compression ratio ... a pain.
2294 #ifdef LIBXML_ZLIB_ENABLED
2295 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2296 xmlGzfileWrite, xmlGzfileClose);
2297 #endif
2299 Nor FTP PUT ....
2300 #ifdef LIBXML_FTP_ENABLED
2301 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2302 xmlIOFTPWrite, xmlIOFTPClose);
2303 #endif
2304 **********************************/
2305 xmlOutputCallbackInitialized = 1;
2308 #ifdef LIBXML_HTTP_ENABLED
2310 * xmlRegisterHTTPPostCallbacks:
2312 * By default, libxml submits HTTP output requests using the "PUT" method.
2313 * Calling this method changes the HTTP output method to use the "POST"
2314 * method instead.
2317 void
2318 xmlRegisterHTTPPostCallbacks( void ) {
2320 /* Register defaults if not done previously */
2322 if ( xmlOutputCallbackInitialized == 0 )
2323 xmlRegisterDefaultOutputCallbacks( );
2325 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2326 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2327 return;
2329 #endif
2330 #endif /* LIBXML_OUTPUT_ENABLED */
2333 * xmlAllocParserInputBuffer:
2334 * @enc: the charset encoding if known
2336 * Create a buffered parser input for progressive parsing
2338 * Returns the new parser input or NULL
2340 xmlParserInputBufferPtr
2341 xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2342 xmlParserInputBufferPtr ret;
2344 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2345 if (ret == NULL) {
2346 xmlIOErrMemory("creating input buffer");
2347 return(NULL);
2349 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
2350 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2351 if (ret->buffer == NULL) {
2352 xmlFree(ret);
2353 return(NULL);
2355 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2356 ret->encoder = xmlGetCharEncodingHandler(enc);
2357 if (ret->encoder != NULL)
2358 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2359 else
2360 ret->raw = NULL;
2361 ret->readcallback = NULL;
2362 ret->closecallback = NULL;
2363 ret->context = NULL;
2364 ret->compressed = -1;
2365 ret->rawconsumed = 0;
2367 return(ret);
2370 #ifdef LIBXML_OUTPUT_ENABLED
2372 * xmlAllocOutputBuffer:
2373 * @encoder: the encoding converter or NULL
2375 * Create a buffered parser output
2377 * Returns the new parser output or NULL
2379 xmlOutputBufferPtr
2380 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2381 xmlOutputBufferPtr ret;
2383 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2384 if (ret == NULL) {
2385 xmlIOErrMemory("creating output buffer");
2386 return(NULL);
2388 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2389 ret->buffer = xmlBufCreate();
2390 if (ret->buffer == NULL) {
2391 xmlFree(ret);
2392 return(NULL);
2394 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2396 ret->encoder = encoder;
2397 if (encoder != NULL) {
2398 ret->conv = xmlBufCreateSize(4000);
2399 if (ret->conv == NULL) {
2400 xmlBufFree(ret->buffer);
2401 xmlFree(ret);
2402 return(NULL);
2406 * This call is designed to initiate the encoder state
2408 xmlCharEncOutput(ret, 1);
2409 } else
2410 ret->conv = NULL;
2411 ret->writecallback = NULL;
2412 ret->closecallback = NULL;
2413 ret->context = NULL;
2414 ret->written = 0;
2416 return(ret);
2420 * xmlAllocOutputBufferInternal:
2421 * @encoder: the encoding converter or NULL
2423 * Create a buffered parser output
2425 * Returns the new parser output or NULL
2427 xmlOutputBufferPtr
2428 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2429 xmlOutputBufferPtr ret;
2431 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2432 if (ret == NULL) {
2433 xmlIOErrMemory("creating output buffer");
2434 return(NULL);
2436 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2437 ret->buffer = xmlBufCreate();
2438 if (ret->buffer == NULL) {
2439 xmlFree(ret);
2440 return(NULL);
2445 * For conversion buffers we use the special IO handling
2447 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
2449 ret->encoder = encoder;
2450 if (encoder != NULL) {
2451 ret->conv = xmlBufCreateSize(4000);
2452 if (ret->conv == NULL) {
2453 xmlBufFree(ret->buffer);
2454 xmlFree(ret);
2455 return(NULL);
2459 * This call is designed to initiate the encoder state
2461 xmlCharEncOutput(ret, 1);
2462 } else
2463 ret->conv = NULL;
2464 ret->writecallback = NULL;
2465 ret->closecallback = NULL;
2466 ret->context = NULL;
2467 ret->written = 0;
2469 return(ret);
2472 #endif /* LIBXML_OUTPUT_ENABLED */
2475 * xmlFreeParserInputBuffer:
2476 * @in: a buffered parser input
2478 * Free up the memory used by a buffered parser input
2480 void
2481 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
2482 if (in == NULL) return;
2484 if (in->raw) {
2485 xmlBufFree(in->raw);
2486 in->raw = NULL;
2488 if (in->encoder != NULL) {
2489 xmlCharEncCloseFunc(in->encoder);
2491 if (in->closecallback != NULL) {
2492 in->closecallback(in->context);
2494 if (in->buffer != NULL) {
2495 xmlBufFree(in->buffer);
2496 in->buffer = NULL;
2499 xmlFree(in);
2502 #ifdef LIBXML_OUTPUT_ENABLED
2504 * xmlOutputBufferClose:
2505 * @out: a buffered output
2507 * flushes and close the output I/O channel
2508 * and free up all the associated resources
2510 * Returns the number of byte written or -1 in case of error.
2513 xmlOutputBufferClose(xmlOutputBufferPtr out)
2515 int written;
2516 int err_rc = 0;
2518 if (out == NULL)
2519 return (-1);
2520 if (out->writecallback != NULL)
2521 xmlOutputBufferFlush(out);
2522 if (out->closecallback != NULL) {
2523 err_rc = out->closecallback(out->context);
2525 written = out->written;
2526 if (out->conv) {
2527 xmlBufFree(out->conv);
2528 out->conv = NULL;
2530 if (out->encoder != NULL) {
2531 xmlCharEncCloseFunc(out->encoder);
2533 if (out->buffer != NULL) {
2534 xmlBufFree(out->buffer);
2535 out->buffer = NULL;
2538 if (out->error)
2539 err_rc = -1;
2540 xmlFree(out);
2541 return ((err_rc == 0) ? written : err_rc);
2543 #endif /* LIBXML_OUTPUT_ENABLED */
2545 xmlParserInputBufferPtr
2546 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2547 xmlParserInputBufferPtr ret;
2548 int i = 0;
2549 void *context = NULL;
2551 if (xmlInputCallbackInitialized == 0)
2552 xmlRegisterDefaultInputCallbacks();
2554 if (URI == NULL) return(NULL);
2557 * Try to find one of the input accept method accepting that scheme
2558 * Go in reverse to give precedence to user defined handlers.
2560 if (context == NULL) {
2561 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2562 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2563 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
2564 context = xmlInputCallbackTable[i].opencallback(URI);
2565 if (context != NULL) {
2566 break;
2571 if (context == NULL) {
2572 return(NULL);
2576 * Allocate the Input buffer front-end.
2578 ret = xmlAllocParserInputBuffer(enc);
2579 if (ret != NULL) {
2580 ret->context = context;
2581 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2582 ret->closecallback = xmlInputCallbackTable[i].closecallback;
2583 #ifdef LIBXML_ZLIB_ENABLED
2584 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2585 (strcmp(URI, "-") != 0)) {
2586 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2587 ret->compressed = !gzdirect(context);
2588 #else
2589 if (((z_stream *)context)->avail_in > 4) {
2590 char *cptr, buff4[4];
2591 cptr = (char *) ((z_stream *)context)->next_in;
2592 if (gzread(context, buff4, 4) == 4) {
2593 if (strncmp(buff4, cptr, 4) == 0)
2594 ret->compressed = 0;
2595 else
2596 ret->compressed = 1;
2597 gzrewind(context);
2600 #endif
2602 #endif
2603 #ifdef LIBXML_LZMA_ENABLED
2604 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2605 (strcmp(URI, "-") != 0)) {
2606 ret->compressed = __libxml2_xzcompressed(context);
2608 #endif
2610 else
2611 xmlInputCallbackTable[i].closecallback (context);
2613 return(ret);
2617 * xmlParserInputBufferCreateFilename:
2618 * @URI: a C string containing the URI or filename
2619 * @enc: the charset encoding if known
2621 * Create a buffered parser input for the progressive parsing of a file
2622 * If filename is "-' then we use stdin as the input.
2623 * Automatic support for ZLIB/Compress compressed document is provided
2624 * by default if found at compile-time.
2625 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2627 * Returns the new parser input or NULL
2629 xmlParserInputBufferPtr
2630 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2631 if ((xmlParserInputBufferCreateFilenameValue)) {
2632 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2634 return __xmlParserInputBufferCreateFilename(URI, enc);
2637 #ifdef LIBXML_OUTPUT_ENABLED
2638 xmlOutputBufferPtr
2639 __xmlOutputBufferCreateFilename(const char *URI,
2640 xmlCharEncodingHandlerPtr encoder,
2641 int compression ATTRIBUTE_UNUSED) {
2642 xmlOutputBufferPtr ret;
2643 xmlURIPtr puri;
2644 int i = 0;
2645 void *context = NULL;
2646 char *unescaped = NULL;
2647 #ifdef LIBXML_ZLIB_ENABLED
2648 int is_file_uri = 1;
2649 #endif
2651 if (xmlOutputCallbackInitialized == 0)
2652 xmlRegisterDefaultOutputCallbacks();
2654 if (URI == NULL) return(NULL);
2656 puri = xmlParseURI(URI);
2657 if (puri != NULL) {
2658 #ifdef LIBXML_ZLIB_ENABLED
2659 if ((puri->scheme != NULL) &&
2660 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2661 is_file_uri = 0;
2662 #endif
2664 * try to limit the damages of the URI unescaping code.
2666 if ((puri->scheme == NULL) ||
2667 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2668 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2669 xmlFreeURI(puri);
2673 * Try to find one of the output accept method accepting that scheme
2674 * Go in reverse to give precedence to user defined handlers.
2675 * try with an unescaped version of the URI
2677 if (unescaped != NULL) {
2678 #ifdef LIBXML_ZLIB_ENABLED
2679 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2680 context = xmlGzfileOpenW(unescaped, compression);
2681 if (context != NULL) {
2682 ret = xmlAllocOutputBufferInternal(encoder);
2683 if (ret != NULL) {
2684 ret->context = context;
2685 ret->writecallback = xmlGzfileWrite;
2686 ret->closecallback = xmlGzfileClose;
2688 xmlFree(unescaped);
2689 return(ret);
2692 #endif
2693 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2694 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2695 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2696 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2697 /* Need to pass compression parameter into HTTP open calls */
2698 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2699 context = xmlIOHTTPOpenW(unescaped, compression);
2700 else
2701 #endif
2702 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2703 if (context != NULL)
2704 break;
2707 xmlFree(unescaped);
2711 * If this failed try with a non-escaped URI this may be a strange
2712 * filename
2714 if (context == NULL) {
2715 #ifdef LIBXML_ZLIB_ENABLED
2716 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2717 context = xmlGzfileOpenW(URI, compression);
2718 if (context != NULL) {
2719 ret = xmlAllocOutputBufferInternal(encoder);
2720 if (ret != NULL) {
2721 ret->context = context;
2722 ret->writecallback = xmlGzfileWrite;
2723 ret->closecallback = xmlGzfileClose;
2725 else
2726 xmlGzfileClose(context);
2727 return(ret);
2730 #endif
2731 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2732 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2733 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
2734 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2735 /* Need to pass compression parameter into HTTP open calls */
2736 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2737 context = xmlIOHTTPOpenW(URI, compression);
2738 else
2739 #endif
2740 context = xmlOutputCallbackTable[i].opencallback(URI);
2741 if (context != NULL)
2742 break;
2747 if (context == NULL) {
2748 return(NULL);
2752 * Allocate the Output buffer front-end.
2754 ret = xmlAllocOutputBufferInternal(encoder);
2755 if (ret != NULL) {
2756 ret->context = context;
2757 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2758 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2760 return(ret);
2764 * xmlOutputBufferCreateFilename:
2765 * @URI: a C string containing the URI or filename
2766 * @encoder: the encoding converter or NULL
2767 * @compression: the compression ration (0 none, 9 max).
2769 * Create a buffered output for the progressive saving of a file
2770 * If filename is "-' then we use stdout as the output.
2771 * Automatic support for ZLIB/Compress compressed document is provided
2772 * by default if found at compile-time.
2773 * TODO: currently if compression is set, the library only support
2774 * writing to a local file.
2776 * Returns the new output or NULL
2778 xmlOutputBufferPtr
2779 xmlOutputBufferCreateFilename(const char *URI,
2780 xmlCharEncodingHandlerPtr encoder,
2781 int compression ATTRIBUTE_UNUSED) {
2782 if ((xmlOutputBufferCreateFilenameValue)) {
2783 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2785 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2787 #endif /* LIBXML_OUTPUT_ENABLED */
2790 * xmlParserInputBufferCreateFile:
2791 * @file: a FILE*
2792 * @enc: the charset encoding if known
2794 * Create a buffered parser input for the progressive parsing of a FILE *
2795 * buffered C I/O
2797 * Returns the new parser input or NULL
2799 xmlParserInputBufferPtr
2800 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2801 xmlParserInputBufferPtr ret;
2803 if (xmlInputCallbackInitialized == 0)
2804 xmlRegisterDefaultInputCallbacks();
2806 if (file == NULL) return(NULL);
2808 ret = xmlAllocParserInputBuffer(enc);
2809 if (ret != NULL) {
2810 ret->context = file;
2811 ret->readcallback = xmlFileRead;
2812 ret->closecallback = xmlFileFlush;
2815 return(ret);
2818 #ifdef LIBXML_OUTPUT_ENABLED
2820 * xmlOutputBufferCreateFile:
2821 * @file: a FILE*
2822 * @encoder: the encoding converter or NULL
2824 * Create a buffered output for the progressive saving to a FILE *
2825 * buffered C I/O
2827 * Returns the new parser output or NULL
2829 xmlOutputBufferPtr
2830 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2831 xmlOutputBufferPtr ret;
2833 if (xmlOutputCallbackInitialized == 0)
2834 xmlRegisterDefaultOutputCallbacks();
2836 if (file == NULL) return(NULL);
2838 ret = xmlAllocOutputBufferInternal(encoder);
2839 if (ret != NULL) {
2840 ret->context = file;
2841 ret->writecallback = xmlFileWrite;
2842 ret->closecallback = xmlFileFlush;
2845 return(ret);
2849 * xmlOutputBufferCreateBuffer:
2850 * @buffer: a xmlBufferPtr
2851 * @encoder: the encoding converter or NULL
2853 * Create a buffered output for the progressive saving to a xmlBuffer
2855 * Returns the new parser output or NULL
2857 xmlOutputBufferPtr
2858 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2859 xmlCharEncodingHandlerPtr encoder) {
2860 xmlOutputBufferPtr ret;
2862 if (buffer == NULL) return(NULL);
2864 ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
2865 encoder);
2867 return(ret);
2871 * xmlOutputBufferGetContent:
2872 * @out: an xmlOutputBufferPtr
2874 * Gives a pointer to the data currently held in the output buffer
2876 * Returns a pointer to the data or NULL in case of error
2878 const xmlChar *
2879 xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2880 if ((out == NULL) || (out->buffer == NULL))
2881 return(NULL);
2883 return(xmlBufContent(out->buffer));
2887 * xmlOutputBufferGetSize:
2888 * @out: an xmlOutputBufferPtr
2890 * Gives the length of the data currently held in the output buffer
2892 * Returns 0 in case or error or no data is held, the size otherwise
2894 size_t
2895 xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2896 if ((out == NULL) || (out->buffer == NULL))
2897 return(0);
2899 return(xmlBufUse(out->buffer));
2903 #endif /* LIBXML_OUTPUT_ENABLED */
2906 * xmlParserInputBufferCreateFd:
2907 * @fd: a file descriptor number
2908 * @enc: the charset encoding if known
2910 * Create a buffered parser input for the progressive parsing for the input
2911 * from a file descriptor
2913 * Returns the new parser input or NULL
2915 xmlParserInputBufferPtr
2916 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2917 xmlParserInputBufferPtr ret;
2919 if (fd < 0) return(NULL);
2921 ret = xmlAllocParserInputBuffer(enc);
2922 if (ret != NULL) {
2923 ret->context = (void *) (ptrdiff_t) fd;
2924 ret->readcallback = xmlFdRead;
2925 ret->closecallback = xmlFdClose;
2928 return(ret);
2932 * xmlParserInputBufferCreateMem:
2933 * @mem: the memory input
2934 * @size: the length of the memory block
2935 * @enc: the charset encoding if known
2937 * Create a buffered parser input for the progressive parsing for the input
2938 * from a memory area.
2940 * Returns the new parser input or NULL
2942 xmlParserInputBufferPtr
2943 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2944 xmlParserInputBufferPtr ret;
2945 int errcode;
2947 if (size < 0) return(NULL);
2948 if (mem == NULL) return(NULL);
2950 ret = xmlAllocParserInputBuffer(enc);
2951 if (ret != NULL) {
2952 ret->context = (void *) mem;
2953 ret->readcallback = xmlInputReadCallbackNop;
2954 ret->closecallback = NULL;
2955 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
2956 if (errcode != 0) {
2957 xmlFree(ret);
2958 return(NULL);
2962 return(ret);
2966 * xmlParserInputBufferCreateStatic:
2967 * @mem: the memory input
2968 * @size: the length of the memory block
2969 * @enc: the charset encoding if known
2971 * Create a buffered parser input for the progressive parsing for the input
2972 * from an immutable memory area. This will not copy the memory area to
2973 * the buffer, but the memory is expected to be available until the end of
2974 * the parsing, this is useful for example when using mmap'ed file.
2976 * Returns the new parser input or NULL
2978 xmlParserInputBufferPtr
2979 xmlParserInputBufferCreateStatic(const char *mem, int size,
2980 xmlCharEncoding enc) {
2981 xmlParserInputBufferPtr ret;
2983 if (size < 0) return(NULL);
2984 if (mem == NULL) return(NULL);
2986 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2987 if (ret == NULL) {
2988 xmlIOErrMemory("creating input buffer");
2989 return(NULL);
2991 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
2992 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
2993 if (ret->buffer == NULL) {
2994 xmlFree(ret);
2995 return(NULL);
2997 ret->encoder = xmlGetCharEncodingHandler(enc);
2998 if (ret->encoder != NULL)
2999 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
3000 else
3001 ret->raw = NULL;
3002 ret->compressed = -1;
3003 ret->context = (void *) mem;
3004 ret->readcallback = NULL;
3005 ret->closecallback = NULL;
3007 return(ret);
3010 #ifdef LIBXML_OUTPUT_ENABLED
3012 * xmlOutputBufferCreateFd:
3013 * @fd: a file descriptor number
3014 * @encoder: the encoding converter or NULL
3016 * Create a buffered output for the progressive saving
3017 * to a file descriptor
3019 * Returns the new parser output or NULL
3021 xmlOutputBufferPtr
3022 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3023 xmlOutputBufferPtr ret;
3025 if (fd < 0) return(NULL);
3027 ret = xmlAllocOutputBufferInternal(encoder);
3028 if (ret != NULL) {
3029 ret->context = (void *) (ptrdiff_t) fd;
3030 ret->writecallback = xmlFdWrite;
3031 ret->closecallback = NULL;
3034 return(ret);
3036 #endif /* LIBXML_OUTPUT_ENABLED */
3039 * xmlParserInputBufferCreateIO:
3040 * @ioread: an I/O read function
3041 * @ioclose: an I/O close function
3042 * @ioctx: an I/O handler
3043 * @enc: the charset encoding if known
3045 * Create a buffered parser input for the progressive parsing for the input
3046 * from an I/O handler
3048 * Returns the new parser input or NULL
3050 xmlParserInputBufferPtr
3051 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3052 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3053 xmlParserInputBufferPtr ret;
3055 if (ioread == NULL) return(NULL);
3057 ret = xmlAllocParserInputBuffer(enc);
3058 if (ret != NULL) {
3059 ret->context = (void *) ioctx;
3060 ret->readcallback = ioread;
3061 ret->closecallback = ioclose;
3064 return(ret);
3067 #ifdef LIBXML_OUTPUT_ENABLED
3069 * xmlOutputBufferCreateIO:
3070 * @iowrite: an I/O write function
3071 * @ioclose: an I/O close function
3072 * @ioctx: an I/O handler
3073 * @encoder: the charset encoding if known
3075 * Create a buffered output for the progressive saving
3076 * to an I/O handler
3078 * Returns the new parser output or NULL
3080 xmlOutputBufferPtr
3081 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3082 xmlOutputCloseCallback ioclose, void *ioctx,
3083 xmlCharEncodingHandlerPtr encoder) {
3084 xmlOutputBufferPtr ret;
3086 if (iowrite == NULL) return(NULL);
3088 ret = xmlAllocOutputBufferInternal(encoder);
3089 if (ret != NULL) {
3090 ret->context = (void *) ioctx;
3091 ret->writecallback = iowrite;
3092 ret->closecallback = ioclose;
3095 return(ret);
3097 #endif /* LIBXML_OUTPUT_ENABLED */
3100 * xmlParserInputBufferCreateFilenameDefault:
3101 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3103 * Registers a callback for URI input file handling
3105 * Returns the old value of the registration function
3107 xmlParserInputBufferCreateFilenameFunc
3108 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3110 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3111 if (old == NULL) {
3112 old = __xmlParserInputBufferCreateFilename;
3115 xmlParserInputBufferCreateFilenameValue = func;
3116 return(old);
3120 * xmlOutputBufferCreateFilenameDefault:
3121 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3123 * Registers a callback for URI output file handling
3125 * Returns the old value of the registration function
3127 xmlOutputBufferCreateFilenameFunc
3128 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3130 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3131 #ifdef LIBXML_OUTPUT_ENABLED
3132 if (old == NULL) {
3133 old = __xmlOutputBufferCreateFilename;
3135 #endif
3136 xmlOutputBufferCreateFilenameValue = func;
3137 return(old);
3141 * xmlParserInputBufferPush:
3142 * @in: a buffered parser input
3143 * @len: the size in bytes of the array.
3144 * @buf: an char array
3146 * Push the content of the arry in the input buffer
3147 * This routine handle the I18N transcoding to internal UTF-8
3148 * This is used when operating the parser in progressive (push) mode.
3150 * Returns the number of chars read and stored in the buffer, or -1
3151 * in case of error.
3154 xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3155 int len, const char *buf) {
3156 int nbchars = 0;
3157 int ret;
3159 if (len < 0) return(0);
3160 if ((in == NULL) || (in->error)) return(-1);
3161 if (in->encoder != NULL) {
3162 unsigned int use;
3165 * Store the data in the incoming raw buffer
3167 if (in->raw == NULL) {
3168 in->raw = xmlBufCreate();
3170 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
3171 if (ret != 0)
3172 return(-1);
3175 * convert as much as possible to the parser reading buffer.
3177 use = xmlBufUse(in->raw);
3178 nbchars = xmlCharEncInput(in, 1);
3179 if (nbchars < 0) {
3180 xmlIOErr(XML_IO_ENCODER, NULL);
3181 in->error = XML_IO_ENCODER;
3182 return(-1);
3184 in->rawconsumed += (use - xmlBufUse(in->raw));
3185 } else {
3186 nbchars = len;
3187 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
3188 if (ret != 0)
3189 return(-1);
3191 #ifdef DEBUG_INPUT
3192 xmlGenericError(xmlGenericErrorContext,
3193 "I/O: pushed %d chars, buffer %d/%d\n",
3194 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
3195 #endif
3196 return(nbchars);
3200 * endOfInput:
3202 * When reading from an Input channel indicated end of file or error
3203 * don't reread from it again.
3205 static int
3206 endOfInput (void * context ATTRIBUTE_UNUSED,
3207 char * buffer ATTRIBUTE_UNUSED,
3208 int len ATTRIBUTE_UNUSED) {
3209 return(0);
3213 * xmlParserInputBufferGrow:
3214 * @in: a buffered parser input
3215 * @len: indicative value of the amount of chars to read
3217 * Grow up the content of the input buffer, the old data are preserved
3218 * This routine handle the I18N transcoding to internal UTF-8
3219 * This routine is used when operating the parser in normal (pull) mode
3221 * TODO: one should be able to remove one extra copy by copying directly
3222 * onto in->buffer or in->raw
3224 * Returns the number of chars read and stored in the buffer, or -1
3225 * in case of error.
3228 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3229 char *buffer = NULL;
3230 int res = 0;
3231 int nbchars = 0;
3233 if ((in == NULL) || (in->error)) return(-1);
3234 if ((len <= MINLEN) && (len != 4))
3235 len = MINLEN;
3237 if (xmlBufAvail(in->buffer) <= 0) {
3238 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
3239 in->error = XML_IO_BUFFER_FULL;
3240 return(-1);
3243 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3244 xmlIOErrMemory("growing input buffer");
3245 in->error = XML_ERR_NO_MEMORY;
3246 return(-1);
3248 buffer = (char *)xmlBufEnd(in->buffer);
3251 * Call the read method for this I/O type.
3253 if (in->readcallback != NULL) {
3254 res = in->readcallback(in->context, &buffer[0], len);
3255 if (res <= 0)
3256 in->readcallback = endOfInput;
3257 } else {
3258 xmlIOErr(XML_IO_NO_INPUT, NULL);
3259 in->error = XML_IO_NO_INPUT;
3260 return(-1);
3262 if (res < 0) {
3263 return(-1);
3267 * try to establish compressed status of input if not done already
3269 if (in->compressed == -1) {
3270 #ifdef LIBXML_LZMA_ENABLED
3271 if (in->readcallback == xmlXzfileRead)
3272 in->compressed = __libxml2_xzcompressed(in->context);
3273 #endif
3276 len = res;
3277 if (in->encoder != NULL) {
3278 unsigned int use;
3281 * Store the data in the incoming raw buffer
3283 if (in->raw == NULL) {
3284 in->raw = xmlBufCreate();
3286 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
3287 if (res != 0)
3288 return(-1);
3291 * convert as much as possible to the parser reading buffer.
3293 use = xmlBufUse(in->raw);
3294 nbchars = xmlCharEncInput(in, 1);
3295 if (nbchars < 0) {
3296 xmlIOErr(XML_IO_ENCODER, NULL);
3297 in->error = XML_IO_ENCODER;
3298 return(-1);
3300 in->rawconsumed += (use - xmlBufUse(in->raw));
3301 } else {
3302 nbchars = len;
3303 xmlBufAddLen(in->buffer, nbchars);
3305 #ifdef DEBUG_INPUT
3306 xmlGenericError(xmlGenericErrorContext,
3307 "I/O: read %d chars, buffer %d\n",
3308 nbchars, xmlBufUse(in->buffer));
3309 #endif
3310 return(nbchars);
3314 * xmlParserInputBufferRead:
3315 * @in: a buffered parser input
3316 * @len: indicative value of the amount of chars to read
3318 * Refresh the content of the input buffer, the old data are considered
3319 * consumed
3320 * This routine handle the I18N transcoding to internal UTF-8
3322 * Returns the number of chars read and stored in the buffer, or -1
3323 * in case of error.
3326 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
3327 if ((in == NULL) || (in->error)) return(-1);
3328 if (in->readcallback != NULL)
3329 return(xmlParserInputBufferGrow(in, len));
3330 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
3331 return(0);
3332 else
3333 return(-1);
3336 #ifdef LIBXML_OUTPUT_ENABLED
3338 * xmlOutputBufferWrite:
3339 * @out: a buffered parser output
3340 * @len: the size in bytes of the array.
3341 * @buf: an char array
3343 * Write the content of the array in the output I/O buffer
3344 * This routine handle the I18N transcoding from internal UTF-8
3345 * The buffer is lossless, i.e. will store in case of partial
3346 * or delayed writes.
3348 * Returns the number of chars immediately written, or -1
3349 * in case of error.
3352 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3353 int nbchars = 0; /* number of chars to output to I/O */
3354 int ret; /* return from function call */
3355 int written = 0; /* number of char written to I/O so far */
3356 int chunk; /* number of byte current processed from buf */
3358 if ((out == NULL) || (out->error)) return(-1);
3359 if (len < 0) return(0);
3360 if (out->error) return(-1);
3362 do {
3363 chunk = len;
3364 if (chunk > 4 * MINLEN)
3365 chunk = 4 * MINLEN;
3368 * first handle encoding stuff.
3370 if (out->encoder != NULL) {
3372 * Store the data in the incoming raw buffer
3374 if (out->conv == NULL) {
3375 out->conv = xmlBufCreate();
3377 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3378 if (ret != 0)
3379 return(-1);
3381 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
3382 goto done;
3385 * convert as much as possible to the parser reading buffer.
3387 ret = xmlCharEncOutput(out, 0);
3388 if ((ret < 0) && (ret != -3)) {
3389 xmlIOErr(XML_IO_ENCODER, NULL);
3390 out->error = XML_IO_ENCODER;
3391 return(-1);
3393 if (out->writecallback)
3394 nbchars = xmlBufUse(out->conv);
3395 else
3396 nbchars = ret >= 0 ? ret : 0;
3397 } else {
3398 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3399 if (ret != 0)
3400 return(-1);
3401 if (out->writecallback)
3402 nbchars = xmlBufUse(out->buffer);
3403 else
3404 nbchars = chunk;
3406 buf += chunk;
3407 len -= chunk;
3409 if (out->writecallback) {
3410 if ((nbchars < MINLEN) && (len <= 0))
3411 goto done;
3414 * second write the stuff to the I/O channel
3416 if (out->encoder != NULL) {
3417 ret = out->writecallback(out->context,
3418 (const char *)xmlBufContent(out->conv), nbchars);
3419 if (ret >= 0)
3420 xmlBufShrink(out->conv, ret);
3421 } else {
3422 ret = out->writecallback(out->context,
3423 (const char *)xmlBufContent(out->buffer), nbchars);
3424 if (ret >= 0)
3425 xmlBufShrink(out->buffer, ret);
3427 if (ret < 0) {
3428 xmlIOErr(XML_IO_WRITE, NULL);
3429 out->error = XML_IO_WRITE;
3430 return(ret);
3432 if (out->written > INT_MAX - ret)
3433 out->written = INT_MAX;
3434 else
3435 out->written += ret;
3437 written += nbchars;
3438 } while (len > 0);
3440 done:
3441 #ifdef DEBUG_INPUT
3442 xmlGenericError(xmlGenericErrorContext,
3443 "I/O: wrote %d chars\n", written);
3444 #endif
3445 return(written);
3449 * xmlEscapeContent:
3450 * @out: a pointer to an array of bytes to store the result
3451 * @outlen: the length of @out
3452 * @in: a pointer to an array of unescaped UTF-8 bytes
3453 * @inlen: the length of @in
3455 * Take a block of UTF-8 chars in and escape them.
3456 * Returns 0 if success, or -1 otherwise
3457 * The value of @inlen after return is the number of octets consumed
3458 * if the return value is positive, else unpredictable.
3459 * The value of @outlen after return is the number of octets consumed.
3461 static int
3462 xmlEscapeContent(unsigned char* out, int *outlen,
3463 const xmlChar* in, int *inlen) {
3464 unsigned char* outstart = out;
3465 const unsigned char* base = in;
3466 unsigned char* outend = out + *outlen;
3467 const unsigned char* inend;
3469 inend = in + (*inlen);
3471 while ((in < inend) && (out < outend)) {
3472 if (*in == '<') {
3473 if (outend - out < 4) break;
3474 *out++ = '&';
3475 *out++ = 'l';
3476 *out++ = 't';
3477 *out++ = ';';
3478 } else if (*in == '>') {
3479 if (outend - out < 4) break;
3480 *out++ = '&';
3481 *out++ = 'g';
3482 *out++ = 't';
3483 *out++ = ';';
3484 } else if (*in == '&') {
3485 if (outend - out < 5) break;
3486 *out++ = '&';
3487 *out++ = 'a';
3488 *out++ = 'm';
3489 *out++ = 'p';
3490 *out++ = ';';
3491 } else if (*in == '\r') {
3492 if (outend - out < 5) break;
3493 *out++ = '&';
3494 *out++ = '#';
3495 *out++ = '1';
3496 *out++ = '3';
3497 *out++ = ';';
3498 } else {
3499 *out++ = (unsigned char) *in;
3501 ++in;
3503 *outlen = out - outstart;
3504 *inlen = in - base;
3505 return(0);
3509 * xmlOutputBufferWriteEscape:
3510 * @out: a buffered parser output
3511 * @str: a zero terminated UTF-8 string
3512 * @escaping: an optional escaping function (or NULL)
3514 * Write the content of the string in the output I/O buffer
3515 * This routine escapes the characters and then handle the I18N
3516 * transcoding from internal UTF-8
3517 * The buffer is lossless, i.e. will store in case of partial
3518 * or delayed writes.
3520 * Returns the number of chars immediately written, or -1
3521 * in case of error.
3524 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3525 xmlCharEncodingOutputFunc escaping) {
3526 int nbchars = 0; /* number of chars to output to I/O */
3527 int ret; /* return from function call */
3528 int written = 0; /* number of char written to I/O so far */
3529 int oldwritten=0;/* loop guard */
3530 int chunk; /* number of byte currently processed from str */
3531 int len; /* number of bytes in str */
3532 int cons; /* byte from str consumed */
3534 if ((out == NULL) || (out->error) || (str == NULL) ||
3535 (out->buffer == NULL) ||
3536 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3537 return(-1);
3538 len = strlen((const char *)str);
3539 if (len < 0) return(0);
3540 if (out->error) return(-1);
3541 if (escaping == NULL) escaping = xmlEscapeContent;
3543 do {
3544 oldwritten = written;
3547 * how many bytes to consume and how many bytes to store.
3549 cons = len;
3550 chunk = xmlBufAvail(out->buffer);
3553 * make sure we have enough room to save first, if this is
3554 * not the case force a flush, but make sure we stay in the loop
3556 if (chunk < 40) {
3557 if (xmlBufGrow(out->buffer, 100) < 0)
3558 return(-1);
3559 oldwritten = -1;
3560 continue;
3564 * first handle encoding stuff.
3566 if (out->encoder != NULL) {
3568 * Store the data in the incoming raw buffer
3570 if (out->conv == NULL) {
3571 out->conv = xmlBufCreate();
3573 ret = escaping(xmlBufEnd(out->buffer) ,
3574 &chunk, str, &cons);
3575 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3576 return(-1);
3577 xmlBufAddLen(out->buffer, chunk);
3579 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
3580 goto done;
3583 * convert as much as possible to the output buffer.
3585 ret = xmlCharEncOutput(out, 0);
3586 if ((ret < 0) && (ret != -3)) {
3587 xmlIOErr(XML_IO_ENCODER, NULL);
3588 out->error = XML_IO_ENCODER;
3589 return(-1);
3591 if (out->writecallback)
3592 nbchars = xmlBufUse(out->conv);
3593 else
3594 nbchars = ret >= 0 ? ret : 0;
3595 } else {
3596 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
3597 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3598 return(-1);
3599 xmlBufAddLen(out->buffer, chunk);
3600 if (out->writecallback)
3601 nbchars = xmlBufUse(out->buffer);
3602 else
3603 nbchars = chunk;
3605 str += cons;
3606 len -= cons;
3608 if (out->writecallback) {
3609 if ((nbchars < MINLEN) && (len <= 0))
3610 goto done;
3613 * second write the stuff to the I/O channel
3615 if (out->encoder != NULL) {
3616 ret = out->writecallback(out->context,
3617 (const char *)xmlBufContent(out->conv), nbchars);
3618 if (ret >= 0)
3619 xmlBufShrink(out->conv, ret);
3620 } else {
3621 ret = out->writecallback(out->context,
3622 (const char *)xmlBufContent(out->buffer), nbchars);
3623 if (ret >= 0)
3624 xmlBufShrink(out->buffer, ret);
3626 if (ret < 0) {
3627 xmlIOErr(XML_IO_WRITE, NULL);
3628 out->error = XML_IO_WRITE;
3629 return(ret);
3631 if (out->written > INT_MAX - ret)
3632 out->written = INT_MAX;
3633 else
3634 out->written += ret;
3635 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3636 xmlBufGrow(out->buffer, MINLEN);
3638 written += nbchars;
3639 } while ((len > 0) && (oldwritten != written));
3641 done:
3642 #ifdef DEBUG_INPUT
3643 xmlGenericError(xmlGenericErrorContext,
3644 "I/O: wrote %d chars\n", written);
3645 #endif
3646 return(written);
3650 * xmlOutputBufferWriteString:
3651 * @out: a buffered parser output
3652 * @str: a zero terminated C string
3654 * Write the content of the string in the output I/O buffer
3655 * This routine handle the I18N transcoding from internal UTF-8
3656 * The buffer is lossless, i.e. will store in case of partial
3657 * or delayed writes.
3659 * Returns the number of chars immediately written, or -1
3660 * in case of error.
3663 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3664 int len;
3666 if ((out == NULL) || (out->error)) return(-1);
3667 if (str == NULL)
3668 return(-1);
3669 len = strlen(str);
3671 if (len > 0)
3672 return(xmlOutputBufferWrite(out, len, str));
3673 return(len);
3677 * xmlOutputBufferFlush:
3678 * @out: a buffered output
3680 * flushes the output I/O channel
3682 * Returns the number of byte written or -1 in case of error.
3685 xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3686 int nbchars = 0, ret = 0;
3688 if ((out == NULL) || (out->error)) return(-1);
3690 * first handle encoding stuff.
3692 if ((out->conv != NULL) && (out->encoder != NULL)) {
3694 * convert as much as possible to the parser output buffer.
3696 do {
3697 nbchars = xmlCharEncOutput(out, 0);
3698 if (nbchars < 0) {
3699 xmlIOErr(XML_IO_ENCODER, NULL);
3700 out->error = XML_IO_ENCODER;
3701 return(-1);
3703 } while (nbchars);
3707 * second flush the stuff to the I/O channel
3709 if ((out->conv != NULL) && (out->encoder != NULL) &&
3710 (out->writecallback != NULL)) {
3711 ret = out->writecallback(out->context,
3712 (const char *)xmlBufContent(out->conv),
3713 xmlBufUse(out->conv));
3714 if (ret >= 0)
3715 xmlBufShrink(out->conv, ret);
3716 } else if (out->writecallback != NULL) {
3717 ret = out->writecallback(out->context,
3718 (const char *)xmlBufContent(out->buffer),
3719 xmlBufUse(out->buffer));
3720 if (ret >= 0)
3721 xmlBufShrink(out->buffer, ret);
3723 if (ret < 0) {
3724 xmlIOErr(XML_IO_FLUSH, NULL);
3725 out->error = XML_IO_FLUSH;
3726 return(ret);
3728 if (out->written > INT_MAX - ret)
3729 out->written = INT_MAX;
3730 else
3731 out->written += ret;
3733 #ifdef DEBUG_INPUT
3734 xmlGenericError(xmlGenericErrorContext,
3735 "I/O: flushed %d chars\n", ret);
3736 #endif
3737 return(ret);
3739 #endif /* LIBXML_OUTPUT_ENABLED */
3742 * xmlParserGetDirectory:
3743 * @filename: the path to a file
3745 * lookup the directory for that file
3747 * Returns a new allocated string containing the directory, or NULL.
3749 char *
3750 xmlParserGetDirectory(const char *filename) {
3751 char *ret = NULL;
3752 char dir[1024];
3753 char *cur;
3755 if (xmlInputCallbackInitialized == 0)
3756 xmlRegisterDefaultInputCallbacks();
3758 if (filename == NULL) return(NULL);
3760 #if defined(_WIN32)
3761 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3762 #else
3763 # define IS_XMLPGD_SEP(ch) (ch=='/')
3764 #endif
3766 strncpy(dir, filename, 1023);
3767 dir[1023] = 0;
3768 cur = &dir[strlen(dir)];
3769 while (cur > dir) {
3770 if (IS_XMLPGD_SEP(*cur)) break;
3771 cur --;
3773 if (IS_XMLPGD_SEP(*cur)) {
3774 if (cur == dir) dir[1] = 0;
3775 else *cur = 0;
3776 ret = xmlMemStrdup(dir);
3777 } else {
3778 if (getcwd(dir, 1024) != NULL) {
3779 dir[1023] = 0;
3780 ret = xmlMemStrdup(dir);
3783 return(ret);
3784 #undef IS_XMLPGD_SEP
3787 /****************************************************************
3789 * External entities loading *
3791 ****************************************************************/
3794 * xmlCheckHTTPInput:
3795 * @ctxt: an XML parser context
3796 * @ret: an XML parser input
3798 * Check an input in case it was created from an HTTP stream, in that
3799 * case it will handle encoding and update of the base URL in case of
3800 * redirection. It also checks for HTTP errors in which case the input
3801 * is cleanly freed up and an appropriate error is raised in context
3803 * Returns the input or NULL in case of HTTP error.
3805 xmlParserInputPtr
3806 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3807 /* Avoid unused variable warning if features are disabled. */
3808 (void) ctxt;
3810 #ifdef LIBXML_HTTP_ENABLED
3811 if ((ret != NULL) && (ret->buf != NULL) &&
3812 (ret->buf->readcallback == xmlIOHTTPRead) &&
3813 (ret->buf->context != NULL)) {
3814 const char *encoding;
3815 const char *redir;
3816 const char *mime;
3817 int code;
3819 code = xmlNanoHTTPReturnCode(ret->buf->context);
3820 if (code >= 400) {
3821 /* fatal error */
3822 if (ret->filename != NULL)
3823 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
3824 (const char *) ret->filename);
3825 else
3826 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
3827 xmlFreeInputStream(ret);
3828 ret = NULL;
3829 } else {
3831 mime = xmlNanoHTTPMimeType(ret->buf->context);
3832 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3833 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3834 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3835 if (encoding != NULL) {
3836 xmlCharEncodingHandlerPtr handler;
3838 handler = xmlFindCharEncodingHandler(encoding);
3839 if (handler != NULL) {
3840 xmlSwitchInputEncoding(ctxt, ret, handler);
3841 } else {
3842 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3843 "Unknown encoding %s",
3844 BAD_CAST encoding, NULL);
3846 if (ret->encoding == NULL)
3847 ret->encoding = xmlStrdup(BAD_CAST encoding);
3849 #if 0
3850 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3851 #endif
3853 redir = xmlNanoHTTPRedir(ret->buf->context);
3854 if (redir != NULL) {
3855 if (ret->filename != NULL)
3856 xmlFree((xmlChar *) ret->filename);
3857 if (ret->directory != NULL) {
3858 xmlFree((xmlChar *) ret->directory);
3859 ret->directory = NULL;
3861 ret->filename =
3862 (char *) xmlStrdup((const xmlChar *) redir);
3866 #endif
3867 return(ret);
3870 static int xmlNoNetExists(const char *URL) {
3871 const char *path;
3873 if (URL == NULL)
3874 return(0);
3876 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
3877 #if defined (_WIN32)
3878 path = &URL[17];
3879 #else
3880 path = &URL[16];
3881 #endif
3882 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
3883 #if defined (_WIN32)
3884 path = &URL[8];
3885 #else
3886 path = &URL[7];
3887 #endif
3888 } else
3889 path = URL;
3891 return xmlCheckFilename(path);
3894 #ifdef LIBXML_CATALOG_ENABLED
3897 * xmlResolveResourceFromCatalog:
3898 * @URL: the URL for the entity to load
3899 * @ID: the System ID for the entity to load
3900 * @ctxt: the context in which the entity is called or NULL
3902 * Resolves the URL and ID against the appropriate catalog.
3903 * This function is used by xmlDefaultExternalEntityLoader and
3904 * xmlNoNetExternalEntityLoader.
3906 * Returns a new allocated URL, or NULL.
3908 static xmlChar *
3909 xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3910 xmlParserCtxtPtr ctxt) {
3911 xmlChar *resource = NULL;
3912 xmlCatalogAllow pref;
3915 * If the resource doesn't exists as a file,
3916 * try to load it from the resource pointed in the catalogs
3918 pref = xmlCatalogGetDefaults();
3920 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3922 * Do a local lookup
3924 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3925 ((pref == XML_CATA_ALLOW_ALL) ||
3926 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3927 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3928 (const xmlChar *)ID,
3929 (const xmlChar *)URL);
3932 * Try a global lookup
3934 if ((resource == NULL) &&
3935 ((pref == XML_CATA_ALLOW_ALL) ||
3936 (pref == XML_CATA_ALLOW_GLOBAL))) {
3937 resource = xmlCatalogResolve((const xmlChar *)ID,
3938 (const xmlChar *)URL);
3940 if ((resource == NULL) && (URL != NULL))
3941 resource = xmlStrdup((const xmlChar *) URL);
3944 * TODO: do an URI lookup on the reference
3946 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3947 xmlChar *tmp = NULL;
3949 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3950 ((pref == XML_CATA_ALLOW_ALL) ||
3951 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3952 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3954 if ((tmp == NULL) &&
3955 ((pref == XML_CATA_ALLOW_ALL) ||
3956 (pref == XML_CATA_ALLOW_GLOBAL))) {
3957 tmp = xmlCatalogResolveURI(resource);
3960 if (tmp != NULL) {
3961 xmlFree(resource);
3962 resource = tmp;
3967 return resource;
3970 #endif
3973 * xmlDefaultExternalEntityLoader:
3974 * @URL: the URL for the entity to load
3975 * @ID: the System ID for the entity to load
3976 * @ctxt: the context in which the entity is called or NULL
3978 * By default we don't load external entities, yet.
3980 * Returns a new allocated xmlParserInputPtr, or NULL.
3982 static xmlParserInputPtr
3983 xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
3984 xmlParserCtxtPtr ctxt)
3986 xmlParserInputPtr ret = NULL;
3987 xmlChar *resource = NULL;
3989 #ifdef DEBUG_EXTERNAL_ENTITIES
3990 xmlGenericError(xmlGenericErrorContext,
3991 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
3992 #endif
3993 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3994 int options = ctxt->options;
3996 ctxt->options -= XML_PARSE_NONET;
3997 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3998 ctxt->options = options;
3999 return(ret);
4001 #ifdef LIBXML_CATALOG_ENABLED
4002 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4003 #endif
4005 if (resource == NULL)
4006 resource = (xmlChar *) URL;
4008 if (resource == NULL) {
4009 if (ID == NULL)
4010 ID = "NULL";
4011 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
4012 return (NULL);
4014 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
4015 if ((resource != NULL) && (resource != (xmlChar *) URL))
4016 xmlFree(resource);
4017 return (ret);
4020 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4021 xmlDefaultExternalEntityLoader;
4024 * xmlSetExternalEntityLoader:
4025 * @f: the new entity resolver function
4027 * Changes the defaultexternal entity resolver function for the application
4029 void
4030 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4031 xmlCurrentExternalEntityLoader = f;
4035 * xmlGetExternalEntityLoader:
4037 * Get the default external entity resolver function for the application
4039 * Returns the xmlExternalEntityLoader function pointer
4041 xmlExternalEntityLoader
4042 xmlGetExternalEntityLoader(void) {
4043 return(xmlCurrentExternalEntityLoader);
4047 * xmlLoadExternalEntity:
4048 * @URL: the URL for the entity to load
4049 * @ID: the Public ID for the entity to load
4050 * @ctxt: the context in which the entity is called or NULL
4052 * Load an external entity, note that the use of this function for
4053 * unparsed entities may generate problems
4055 * Returns the xmlParserInputPtr or NULL
4057 xmlParserInputPtr
4058 xmlLoadExternalEntity(const char *URL, const char *ID,
4059 xmlParserCtxtPtr ctxt) {
4060 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
4061 char *canonicFilename;
4062 xmlParserInputPtr ret;
4064 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4065 if (canonicFilename == NULL) {
4066 xmlIOErrMemory("building canonical path\n");
4067 return(NULL);
4070 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4071 xmlFree(canonicFilename);
4072 return(ret);
4074 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4077 /************************************************************************
4079 * Disabling Network access *
4081 ************************************************************************/
4084 * xmlNoNetExternalEntityLoader:
4085 * @URL: the URL for the entity to load
4086 * @ID: the System ID for the entity to load
4087 * @ctxt: the context in which the entity is called or NULL
4089 * A specific entity loader disabling network accesses, though still
4090 * allowing local catalog accesses for resolution.
4092 * Returns a new allocated xmlParserInputPtr, or NULL.
4094 xmlParserInputPtr
4095 xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4096 xmlParserCtxtPtr ctxt) {
4097 xmlParserInputPtr input = NULL;
4098 xmlChar *resource = NULL;
4100 #ifdef LIBXML_CATALOG_ENABLED
4101 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4102 #endif
4104 if (resource == NULL)
4105 resource = (xmlChar *) URL;
4107 if (resource != NULL) {
4108 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4109 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
4110 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
4111 if (resource != (xmlChar *) URL)
4112 xmlFree(resource);
4113 return(NULL);
4116 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4117 if (resource != (xmlChar *) URL)
4118 xmlFree(resource);
4119 return(input);