2 * xmlIO.c : implementation of the I/O interfaces used by the parser
4 * See Copyright for the status of this software.
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
20 #ifdef HAVE_SYS_TYPES_H
21 #include <sys/types.h>
23 #ifdef HAVE_SYS_STAT_H
42 #if defined(WIN32) || defined(_WIN32)
46 #if defined(_WIN32_WCE)
47 #include <winnls.h> /* for CP_UTF8 */
50 /* Figure a portable way to know if a file is a directory. */
53 /* MS C library seems to define stat and _stat. The definition
54 is identical. Still, mapping them to each other causes a warning. */
56 # define stat(x,y) _stat(x,y)
62 # if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
70 # define S_ISDIR(x) _S_ISDIR(x)
75 # define S_IFMT _S_IFMT
79 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
86 #include <libxml/xmlmemory.h>
87 #include <libxml/parser.h>
88 #include <libxml/parserInternals.h>
89 #include <libxml/xmlIO.h>
90 #include <libxml/uri.h>
91 #include <libxml/nanohttp.h>
92 #include <libxml/nanoftp.h>
93 #include <libxml/xmlerror.h>
94 #ifdef LIBXML_CATALOG_ENABLED
95 #include <libxml/catalog.h>
97 #include <libxml/globals.h>
102 /* #define VERBOSE_FAILURE */
103 /* #define DEBUG_EXTERNAL_ENTITIES */
104 /* #define DEBUG_INPUT */
113 * Input I/O callback sets
115 typedef struct _xmlInputCallback {
116 xmlInputMatchCallback matchcallback;
117 xmlInputOpenCallback opencallback;
118 xmlInputReadCallback readcallback;
119 xmlInputCloseCallback closecallback;
122 #define MAX_INPUT_CALLBACK 15
124 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
125 static int xmlInputCallbackNr = 0;
126 static int xmlInputCallbackInitialized = 0;
128 #ifdef LIBXML_OUTPUT_ENABLED
130 * Output I/O callback sets
132 typedef struct _xmlOutputCallback {
133 xmlOutputMatchCallback matchcallback;
134 xmlOutputOpenCallback opencallback;
135 xmlOutputWriteCallback writecallback;
136 xmlOutputCloseCallback closecallback;
139 #define MAX_OUTPUT_CALLBACK 15
141 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
142 static int xmlOutputCallbackNr = 0;
143 static int xmlOutputCallbackInitialized = 0;
146 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
147 #endif /* LIBXML_OUTPUT_ENABLED */
149 /************************************************************************
151 * Tree memory error handler *
153 ************************************************************************/
155 static const char *IOerr[] = {
156 "Unknown IO error", /* UNKNOWN */
157 "Permission denied", /* EACCES */
158 "Resource temporarily unavailable",/* EAGAIN */
159 "Bad file descriptor", /* EBADF */
160 "Bad message", /* EBADMSG */
161 "Resource busy", /* EBUSY */
162 "Operation canceled", /* ECANCELED */
163 "No child processes", /* ECHILD */
164 "Resource deadlock avoided",/* EDEADLK */
165 "Domain error", /* EDOM */
166 "File exists", /* EEXIST */
167 "Bad address", /* EFAULT */
168 "File too large", /* EFBIG */
169 "Operation in progress", /* EINPROGRESS */
170 "Interrupted function call",/* EINTR */
171 "Invalid argument", /* EINVAL */
172 "Input/output error", /* EIO */
173 "Is a directory", /* EISDIR */
174 "Too many open files", /* EMFILE */
175 "Too many links", /* EMLINK */
176 "Inappropriate message buffer length",/* EMSGSIZE */
177 "Filename too long", /* ENAMETOOLONG */
178 "Too many open files in system",/* ENFILE */
179 "No such device", /* ENODEV */
180 "No such file or directory",/* ENOENT */
181 "Exec format error", /* ENOEXEC */
182 "No locks available", /* ENOLCK */
183 "Not enough space", /* ENOMEM */
184 "No space left on device", /* ENOSPC */
185 "Function not implemented", /* ENOSYS */
186 "Not a directory", /* ENOTDIR */
187 "Directory not empty", /* ENOTEMPTY */
188 "Not supported", /* ENOTSUP */
189 "Inappropriate I/O control operation",/* ENOTTY */
190 "No such device or address",/* ENXIO */
191 "Operation not permitted", /* EPERM */
192 "Broken pipe", /* EPIPE */
193 "Result too large", /* ERANGE */
194 "Read-only file system", /* EROFS */
195 "Invalid seek", /* ESPIPE */
196 "No such process", /* ESRCH */
197 "Operation timed out", /* ETIMEDOUT */
198 "Improper link", /* EXDEV */
199 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
200 "encoder error", /* XML_IO_ENCODER */
206 "not a socket", /* ENOTSOCK */
207 "already connected", /* EISCONN */
208 "connection refused", /* ECONNREFUSED */
209 "unreachable network", /* ENETUNREACH */
210 "adddress in use", /* EADDRINUSE */
211 "already in use", /* EALREADY */
212 "unknown address familly", /* EAFNOSUPPORT */
215 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
217 * __xmlIOWin32UTF8ToWChar:
218 * @u8String: uft-8 string
220 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
223 __xmlIOWin32UTF8ToWChar(const char *u8String)
225 wchar_t *wString = NULL;
229 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
232 wString = xmlMalloc(wLen * sizeof(wchar_t));
234 if (MultiByteToWideChar
235 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
249 * @extra: extra informations
251 * Handle an out of memory condition
254 xmlIOErrMemory(const char *extra)
256 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
261 * @code: the error number
263 * @extra: extra informations
265 * Handle an I/O error
268 __xmlIOErr(int domain, int code, const char *extra)
274 if (errno == 0) code = 0;
276 else if (errno == EACCES) code = XML_IO_EACCES;
279 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
282 else if (errno == EBADF) code = XML_IO_EBADF;
285 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
288 else if (errno == EBUSY) code = XML_IO_EBUSY;
291 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
294 else if (errno == ECHILD) code = XML_IO_ECHILD;
297 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
300 else if (errno == EDOM) code = XML_IO_EDOM;
303 else if (errno == EEXIST) code = XML_IO_EEXIST;
306 else if (errno == EFAULT) code = XML_IO_EFAULT;
309 else if (errno == EFBIG) code = XML_IO_EFBIG;
312 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
315 else if (errno == EINTR) code = XML_IO_EINTR;
318 else if (errno == EINVAL) code = XML_IO_EINVAL;
321 else if (errno == EIO) code = XML_IO_EIO;
324 else if (errno == EISDIR) code = XML_IO_EISDIR;
327 else if (errno == EMFILE) code = XML_IO_EMFILE;
330 else if (errno == EMLINK) code = XML_IO_EMLINK;
333 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
336 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
339 else if (errno == ENFILE) code = XML_IO_ENFILE;
342 else if (errno == ENODEV) code = XML_IO_ENODEV;
345 else if (errno == ENOENT) code = XML_IO_ENOENT;
348 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
351 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
354 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
357 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
360 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
363 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
366 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
369 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
372 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
375 else if (errno == ENXIO) code = XML_IO_ENXIO;
378 else if (errno == EPERM) code = XML_IO_EPERM;
381 else if (errno == EPIPE) code = XML_IO_EPIPE;
384 else if (errno == ERANGE) code = XML_IO_ERANGE;
387 else if (errno == EROFS) code = XML_IO_EROFS;
390 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
393 else if (errno == ESRCH) code = XML_IO_ESRCH;
396 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
399 else if (errno == EXDEV) code = XML_IO_EXDEV;
402 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
405 else if (errno == EISCONN) code = XML_IO_EISCONN;
408 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
411 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
414 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
417 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
420 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
423 else if (errno == EALREADY) code = XML_IO_EALREADY;
426 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
428 else code = XML_IO_UNKNOWN;
429 #endif /* HAVE_ERRNO_H */
432 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
433 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
435 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
440 * @code: the error number
441 * @extra: extra informations
443 * Handle an I/O error
446 xmlIOErr(int code, const char *extra)
448 __xmlIOErr(XML_FROM_IO, code, extra);
453 * @ctx: the parser context
454 * @extra: extra informations
456 * Handle a resource access error
459 __xmlLoaderErr(void *ctx, const char *msg, const char *filename)
461 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
462 xmlStructuredErrorFunc schannel = NULL;
463 xmlGenericErrorFunc channel = NULL;
465 xmlErrorLevel level = XML_ERR_ERROR;
467 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
468 (ctxt->instate == XML_PARSER_EOF))
470 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
471 if (ctxt->validate) {
472 channel = ctxt->sax->error;
473 level = XML_ERR_ERROR;
475 channel = ctxt->sax->warning;
476 level = XML_ERR_WARNING;
478 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
479 schannel = ctxt->sax->serror;
480 data = ctxt->userData;
482 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
483 XML_IO_LOAD_ERROR, level, NULL, 0,
484 filename, NULL, NULL, 0, 0,
489 /************************************************************************
491 * Tree memory error handler *
493 ************************************************************************/
495 * xmlNormalizeWindowsPath:
496 * @path: the input file path
498 * This function is obsolete. Please see xmlURIFromPath in uri.c for
501 * Returns a canonicalized version of the path
504 xmlNormalizeWindowsPath(const xmlChar *path)
506 return xmlCanonicPath(path);
510 * xmlCleanupInputCallbacks:
512 * clears the entire input callback table. this includes the
516 xmlCleanupInputCallbacks(void)
520 if (!xmlInputCallbackInitialized)
523 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
524 xmlInputCallbackTable[i].matchcallback = NULL;
525 xmlInputCallbackTable[i].opencallback = NULL;
526 xmlInputCallbackTable[i].readcallback = NULL;
527 xmlInputCallbackTable[i].closecallback = NULL;
530 xmlInputCallbackNr = 0;
531 xmlInputCallbackInitialized = 0;
535 * xmlPopInputCallbacks:
537 * Clear the top input callback from the input stack. this includes the
540 * Returns the number of input callback registered or -1 in case of error.
543 xmlPopInputCallbacks(void)
545 if (!xmlInputCallbackInitialized)
548 if (xmlInputCallbackNr <= 0)
551 xmlInputCallbackNr--;
552 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
553 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
554 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
555 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
557 return(xmlInputCallbackNr);
560 #ifdef LIBXML_OUTPUT_ENABLED
562 * xmlCleanupOutputCallbacks:
564 * clears the entire output callback table. this includes the
565 * compiled-in I/O callbacks.
568 xmlCleanupOutputCallbacks(void)
572 if (!xmlOutputCallbackInitialized)
575 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
576 xmlOutputCallbackTable[i].matchcallback = NULL;
577 xmlOutputCallbackTable[i].opencallback = NULL;
578 xmlOutputCallbackTable[i].writecallback = NULL;
579 xmlOutputCallbackTable[i].closecallback = NULL;
582 xmlOutputCallbackNr = 0;
583 xmlOutputCallbackInitialized = 0;
585 #endif /* LIBXML_OUTPUT_ENABLED */
587 /************************************************************************
589 * Standard I/O for file accesses *
591 ************************************************************************/
593 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
597 * @path: the path in utf-8 encoding
598 * @mode: type of access (0 - read, 1 - write)
600 * function opens the file specified by @path
604 xmlWrapOpenUtf8(const char *path,int mode)
609 wPath = __xmlIOWin32UTF8ToWChar(path);
612 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
615 /* maybe path in native encoding */
617 fd = fopen(path, mode ? "wb" : "rb");
624 xmlWrapGzOpenUtf8(const char *path, const char *mode)
629 fd = gzopen (path, mode);
633 wPath = __xmlIOWin32UTF8ToWChar(path);
636 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
638 m |= (strstr(mode, "b") ? _O_BINARY : 0);
640 d = _wopen(wPath, m);
642 fd = gzdopen(d, mode);
652 * @path: the path in utf-8 encoding
653 * @info: structure that stores results
655 * function obtains information about the file or directory
659 xmlWrapStatUtf8(const char *path,struct stat *info)
665 wPath = __xmlIOWin32UTF8ToWChar(path);
668 retval = _wstat(wPath,info);
671 /* maybe path in native encoding */
673 retval = stat(path,info);
683 * @mode: type of access (0 - read, 1 - write)
685 * function opens the file specified by @path
689 xmlWrapOpenNative(const char *path,int mode)
691 return fopen(path,mode ? "wb" : "rb");
697 * @info: structure that stores results
699 * function obtains information about the file or directory
703 xmlWrapStatNative(const char *path,struct stat *info)
706 return stat(path,info);
712 typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
713 static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
714 typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
715 static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
717 typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
718 static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
721 * xmlInitPlatformSpecificIo:
723 * Initialize platform specific features.
726 xmlInitPlatformSpecificIo(void)
728 static int xmlPlatformIoInitialized = 0;
731 if(xmlPlatformIoInitialized)
734 osvi.dwOSVersionInfoSize = sizeof(osvi);
736 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
737 xmlWrapStat = xmlWrapStatUtf8;
738 xmlWrapOpen = xmlWrapOpenUtf8;
740 xmlWrapGzOpen = xmlWrapGzOpenUtf8;
743 xmlWrapStat = xmlWrapStatNative;
744 xmlWrapOpen = xmlWrapOpenNative;
746 xmlWrapGzOpen = gzopen;
750 xmlPlatformIoInitialized = 1;
758 * @path: the path to check
760 * function checks to see if @path is a valid source
761 * (file, socket...) for XML.
763 * if stat is not available on the target machine,
764 * returns 1. if stat fails, returns 0 (if calling
765 * stat on the filename fails, it can't be right).
766 * if stat succeeds and the file is a directory,
767 * returns 2. otherwise returns 1.
771 xmlCheckFilename (const char *path)
774 struct stat stat_buffer;
780 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
782 * On Windows stat and wstat do not work with long pathname,
783 * which start with '\\?\'
785 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
789 if (xmlWrapStat(path, &stat_buffer) == -1)
792 if (stat(path, &stat_buffer) == -1)
796 if (S_ISDIR(stat_buffer.st_mode))
799 #endif /* HAVE_STAT */
806 * No Operation function, does nothing, no input
817 * @context: the I/O context
818 * @buffer: where to drop data
819 * @len: number of bytes to read
821 * Read @len bytes to @buffer from the I/O channel.
823 * Returns the number of bytes written
826 xmlFdRead (void * context, char * buffer, int len) {
829 ret = read((int) (long) context, &buffer[0], len);
830 if (ret < 0) xmlIOErr(0, "read()");
834 #ifdef LIBXML_OUTPUT_ENABLED
837 * @context: the I/O context
838 * @buffer: where to get data
839 * @len: number of bytes to write
841 * Write @len bytes from @buffer to the I/O channel.
843 * Returns the number of bytes written
846 xmlFdWrite (void * context, const char * buffer, int len) {
850 ret = write((int) (long) context, &buffer[0], len);
851 if (ret < 0) xmlIOErr(0, "write()");
855 #endif /* LIBXML_OUTPUT_ENABLED */
859 * @context: the I/O context
861 * Close an I/O channel
863 * Returns 0 in case of success and error code otherwise
866 xmlFdClose (void * context) {
868 ret = close((int) (long) context);
869 if (ret < 0) xmlIOErr(0, "close()");
875 * @filename: the URI for matching
879 * Returns 1 if matches, 0 otherwise
882 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
888 * @filename: the URI for matching
890 * input from FILE *, supports compressed input
891 * if @filename is " " then the standard input is used
893 * Returns an I/O context or NULL in case of error
896 xmlFileOpen_real (const char *filename) {
897 const char *path = filename;
900 if (filename == NULL)
903 if (!strcmp(filename, "-")) {
908 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
909 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
910 path = &filename[17];
912 path = &filename[16];
914 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
915 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
920 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
921 /* lots of generators seems to lazy to read RFC 1738 */
922 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
929 /* Do not check DDNAME on zOS ! */
930 #if !defined(__MVS__)
931 if (!xmlCheckFilename(path))
935 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
936 fd = xmlWrapOpen(path, 0);
938 fd = fopen(path, "r");
940 if (fd == NULL) xmlIOErr(0, path);
946 * @filename: the URI for matching
948 * Wrapper around xmlFileOpen_real that try it with an unescaped
949 * version of @filename, if this fails fallback to @filename
951 * Returns a handler or NULL in case or failure
954 xmlFileOpen (const char *filename) {
958 retval = xmlFileOpen_real(filename);
959 if (retval == NULL) {
960 unescaped = xmlURIUnescapeString(filename, 0, NULL);
961 if (unescaped != NULL) {
962 retval = xmlFileOpen_real(unescaped);
970 #ifdef LIBXML_OUTPUT_ENABLED
973 * @filename: the URI for matching
975 * output to from FILE *,
976 * if @filename is "-" then the standard output is used
978 * Returns an I/O context or NULL in case of error
981 xmlFileOpenW (const char *filename) {
982 const char *path = NULL;
985 if (!strcmp(filename, "-")) {
990 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
991 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
992 path = &filename[17];
994 path = &filename[16];
996 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
997 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1000 path = &filename[7];
1008 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1009 fd = xmlWrapOpen(path, 1);
1011 fd = fopen(path, "w");
1013 fd = fopen(path, "wb");
1016 if (fd == NULL) xmlIOErr(0, path);
1017 return((void *) fd);
1019 #endif /* LIBXML_OUTPUT_ENABLED */
1023 * @context: the I/O context
1024 * @buffer: where to drop data
1025 * @len: number of bytes to write
1027 * Read @len bytes to @buffer from the I/O channel.
1029 * Returns the number of bytes written or < 0 in case of failure
1032 xmlFileRead (void * context, char * buffer, int len) {
1034 if ((context == NULL) || (buffer == NULL))
1036 ret = fread(&buffer[0], 1, len, (FILE *) context);
1037 if (ret < 0) xmlIOErr(0, "fread()");
1041 #ifdef LIBXML_OUTPUT_ENABLED
1044 * @context: the I/O context
1045 * @buffer: where to drop data
1046 * @len: number of bytes to write
1048 * Write @len bytes from @buffer to the I/O channel.
1050 * Returns the number of bytes written
1053 xmlFileWrite (void * context, const char * buffer, int len) {
1056 if ((context == NULL) || (buffer == NULL))
1058 items = fwrite(&buffer[0], len, 1, (FILE *) context);
1059 if ((items == 0) && (ferror((FILE *) context))) {
1060 xmlIOErr(0, "fwrite()");
1063 return(items * len);
1065 #endif /* LIBXML_OUTPUT_ENABLED */
1069 * @context: the I/O context
1071 * Close an I/O channel
1073 * Returns 0 or -1 in case of error
1076 xmlFileClose (void * context) {
1080 if (context == NULL)
1082 fil = (FILE *) context;
1083 if ((fil == stdout) || (fil == stderr)) {
1086 xmlIOErr(0, "fflush()");
1091 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1093 xmlIOErr(0, "fclose()");
1099 * @context: the I/O context
1101 * Flush an I/O channel
1104 xmlFileFlush (void * context) {
1107 if (context == NULL)
1109 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1111 xmlIOErr(0, "fflush()");
1115 #ifdef LIBXML_OUTPUT_ENABLED
1118 * @context: the xmlBuffer
1119 * @buffer: the data to write
1120 * @len: number of bytes to write
1122 * Write @len bytes from @buffer to the xml buffer
1124 * Returns the number of bytes written
1127 xmlBufferWrite (void * context, const char * buffer, int len) {
1130 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1138 /************************************************************************
1140 * I/O for compressed file accesses *
1142 ************************************************************************/
1145 * @filename: the URI for matching
1147 * input from compressed file test
1149 * Returns 1 if matches, 0 otherwise
1152 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1157 * xmlGzfileOpen_real:
1158 * @filename: the URI for matching
1160 * input from compressed file open
1161 * if @filename is " " then the standard input is used
1163 * Returns an I/O context or NULL in case of error
1166 xmlGzfileOpen_real (const char *filename) {
1167 const char *path = NULL;
1170 if (!strcmp(filename, "-")) {
1171 int duped_fd = dup(fileno(stdin));
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) || defined (__DJGPP__) && !defined(__CYGWIN__)
1182 path = &filename[17];
1184 path = &filename[16];
1186 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1187 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1188 path = &filename[8];
1190 path = &filename[7];
1197 if (!xmlCheckFilename(path))
1200 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1201 fd = xmlWrapGzOpen(path, "rb");
1203 fd = gzopen(path, "rb");
1205 return((void *) fd);
1210 * @filename: the URI for matching
1212 * Wrapper around xmlGzfileOpen if the open fais, it will
1213 * try to unescape @filename
1216 xmlGzfileOpen (const char *filename) {
1220 retval = xmlGzfileOpen_real(filename);
1221 if (retval == NULL) {
1222 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1223 if (unescaped != NULL) {
1224 retval = xmlGzfileOpen_real(unescaped);
1231 #ifdef LIBXML_OUTPUT_ENABLED
1234 * @filename: the URI for matching
1235 * @compression: the compression factor (0 - 9 included)
1237 * input from compressed file open
1238 * if @filename is " " then the standard input is used
1240 * Returns an I/O context or NULL in case of error
1243 xmlGzfileOpenW (const char *filename, int compression) {
1244 const char *path = NULL;
1248 snprintf(mode, sizeof(mode), "wb%d", compression);
1249 if (!strcmp(filename, "-")) {
1250 int duped_fd = dup(fileno(stdout));
1251 fd = gzdopen(duped_fd, "rb");
1252 if (fd == Z_NULL && duped_fd >= 0) {
1253 close(duped_fd); /* gzdOpen() does not close on failure */
1256 return((void *) fd);
1259 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
1260 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1261 path = &filename[17];
1263 path = &filename[16];
1265 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1266 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1267 path = &filename[8];
1269 path = &filename[7];
1277 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1278 fd = xmlWrapGzOpen(path, mode);
1280 fd = gzopen(path, mode);
1282 return((void *) fd);
1284 #endif /* LIBXML_OUTPUT_ENABLED */
1288 * @context: the I/O context
1289 * @buffer: where to drop data
1290 * @len: number of bytes to write
1292 * Read @len bytes to @buffer from the compressed I/O channel.
1294 * Returns the number of bytes read.
1297 xmlGzfileRead (void * context, char * buffer, int len) {
1300 ret = gzread((gzFile) context, &buffer[0], len);
1301 if (ret < 0) xmlIOErr(0, "gzread()");
1305 #ifdef LIBXML_OUTPUT_ENABLED
1308 * @context: the I/O context
1309 * @buffer: where to drop data
1310 * @len: number of bytes to write
1312 * Write @len bytes from @buffer to the compressed I/O channel.
1314 * Returns the number of bytes written
1317 xmlGzfileWrite (void * context, const char * buffer, int len) {
1320 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1321 if (ret < 0) xmlIOErr(0, "gzwrite()");
1324 #endif /* LIBXML_OUTPUT_ENABLED */
1328 * @context: the I/O context
1330 * Close a compressed I/O channel
1333 xmlGzfileClose (void * context) {
1336 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1337 if (ret < 0) xmlIOErr(0, "gzclose()");
1340 #endif /* HAVE_ZLIB_H */
1342 #ifdef LIBXML_LZMA_ENABLED
1343 /************************************************************************
1345 * I/O for compressed file accesses *
1347 ************************************************************************/
1351 * @filename: the URI for matching
1353 * input from compressed file test
1355 * Returns 1 if matches, 0 otherwise
1358 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1363 * xmlXzFileOpen_real:
1364 * @filename: the URI for matching
1366 * input from compressed file open
1367 * if @filename is " " then the standard input is used
1369 * Returns an I/O context or NULL in case of error
1372 xmlXzfileOpen_real (const char *filename) {
1373 const char *path = NULL;
1376 if (!strcmp(filename, "-")) {
1377 fd = __libxml2_xzdopen(dup(fileno(stdin)), "rb");
1378 return((void *) fd);
1381 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1382 path = &filename[16];
1383 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1384 path = &filename[7];
1385 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1386 /* lots of generators seems to lazy to read RFC 1738 */
1387 path = &filename[5];
1393 if (!xmlCheckFilename(path))
1396 fd = __libxml2_xzopen(path, "rb");
1397 return((void *) fd);
1402 * @filename: the URI for matching
1404 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1405 * version of @filename, if this fails fallback to @filename
1407 * Returns a handler or NULL in case or failure
1410 xmlXzfileOpen (const char *filename) {
1414 retval = xmlXzfileOpen_real(filename);
1415 if (retval == NULL) {
1416 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1417 if (unescaped != NULL) {
1418 retval = xmlXzfileOpen_real(unescaped);
1428 * @context: the I/O context
1429 * @buffer: where to drop data
1430 * @len: number of bytes to write
1432 * Read @len bytes to @buffer from the compressed I/O channel.
1434 * Returns the number of bytes written
1437 xmlXzfileRead (void * context, char * buffer, int len) {
1440 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
1441 if (ret < 0) xmlIOErr(0, "xzread()");
1447 * @context: the I/O context
1449 * Close a compressed I/O channel
1452 xmlXzfileClose (void * context) {
1455 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
1456 if (ret < 0) xmlIOErr(0, "xzclose()");
1459 #endif /* LIBXML_LZMA_ENABLED */
1461 #ifdef LIBXML_HTTP_ENABLED
1462 /************************************************************************
1464 * I/O for HTTP file accesses *
1466 ************************************************************************/
1468 #ifdef LIBXML_OUTPUT_ENABLED
1469 typedef struct xmlIOHTTPWriteCtxt_
1477 } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1481 #define DFLT_WBITS ( -15 )
1482 #define DFLT_MEM_LVL ( 8 )
1483 #define GZ_MAGIC1 ( 0x1f )
1484 #define GZ_MAGIC2 ( 0x8b )
1485 #define LXML_ZLIB_OS_CODE ( 0x03 )
1486 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1487 #define DFLT_ZLIB_RATIO ( 5 )
1490 ** Data structure and functions to work with sending compressed data
1494 typedef struct xmlZMemBuff_
1499 unsigned char * zbuff;
1502 } xmlZMemBuff, *xmlZMemBuffPtr;
1505 * append_reverse_ulong
1506 * @buff: Compressed memory buffer
1507 * @data: Unsigned long to append
1509 * Append a unsigned long in reverse byte order to the end of the
1513 append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1521 ** This is plagiarized from putLong in gzio.c (zlib source) where
1522 ** the number "4" is hardcoded. If zlib is ever patched to
1523 ** support 64 bit file sizes, this code would need to be patched
1527 for ( idx = 0; idx < 4; idx++ ) {
1528 *buff->zctrl.next_out = ( data & 0xff );
1530 buff->zctrl.next_out++;
1539 * @buff: The memory buffer context to clear
1541 * Release all the resources associated with the compressed memory buffer.
1544 xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
1553 xmlFree( buff->zbuff );
1555 z_err = deflateEnd( &buff->zctrl );
1556 if ( z_err != Z_OK )
1557 xmlGenericError( xmlGenericErrorContext,
1558 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1561 deflateEnd( &buff->zctrl );
1570 *@compression: Compression value to use
1572 * Create a memory buffer to hold the compressed XML document. The
1573 * compressed document in memory will end up being identical to what
1574 * would be created if gzopen/gzwrite/gzclose were being used to
1575 * write the document to disk. The code for the header/trailer data to
1576 * the compression is plagiarized from the zlib source files.
1579 xmlCreateZMemBuff( int compression ) {
1583 xmlZMemBuffPtr buff = NULL;
1585 if ( ( compression < 1 ) || ( compression > 9 ) )
1588 /* Create the control and data areas */
1590 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1591 if ( buff == NULL ) {
1592 xmlIOErrMemory("creating buffer context");
1596 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1597 buff->size = INIT_HTTP_BUFF_SIZE;
1598 buff->zbuff = xmlMalloc( buff->size );
1599 if ( buff->zbuff == NULL ) {
1600 xmlFreeZMemBuff( buff );
1601 xmlIOErrMemory("creating buffer");
1605 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1606 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1607 if ( z_err != Z_OK ) {
1609 xmlFreeZMemBuff( buff );
1611 xmlStrPrintf(msg, 500,
1612 "xmlCreateZMemBuff: %s %d\n",
1613 "Error initializing compression context. ZLIB error:",
1615 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1619 /* Set the header data. The CRC will be needed for the trailer */
1620 buff->crc = crc32( 0L, NULL, 0 );
1621 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1622 "%c%c%c%c%c%c%c%c%c%c",
1623 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1624 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1625 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1626 buff->zctrl.avail_out = buff->size - hdr_lgth;
1633 * @buff: Buffer used to compress and consolidate data.
1634 * @ext_amt: Number of bytes to extend the buffer.
1636 * Extend the internal buffer used to store the compressed data by the
1639 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1640 * the original buffer still exists at the original size.
1643 xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1649 unsigned char * tmp_ptr = NULL;
1654 else if ( ext_amt == 0 )
1657 cur_used = buff->zctrl.next_out - buff->zbuff;
1658 new_size = buff->size + ext_amt;
1661 if ( cur_used > new_size )
1662 xmlGenericError( xmlGenericErrorContext,
1663 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1664 "Buffer overwrite detected during compressed memory",
1665 "buffer extension. Overflowed by",
1666 (cur_used - new_size ) );
1669 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1670 if ( tmp_ptr != NULL ) {
1672 buff->size = new_size;
1673 buff->zbuff = tmp_ptr;
1674 buff->zctrl.next_out = tmp_ptr + cur_used;
1675 buff->zctrl.avail_out = new_size - cur_used;
1679 xmlStrPrintf(msg, 500,
1680 "xmlZMemBuffExtend: %s %lu bytes.\n",
1681 "Allocation failure extending output buffer to",
1682 (unsigned long) new_size );
1683 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1691 * @buff: Buffer used to compress and consolidate data
1692 * @src: Uncompressed source content to append to buffer
1693 * @len: Length of source data to append to buffer
1695 * Compress and append data to the internal buffer. The data buffer
1696 * will be expanded if needed to store the additional data.
1698 * Returns the number of bytes appended to the buffer or -1 on error.
1701 xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1706 if ( ( buff == NULL ) || ( src == NULL ) )
1709 buff->zctrl.avail_in = len;
1710 buff->zctrl.next_in = (unsigned char *)src;
1711 while ( buff->zctrl.avail_in > 0 ) {
1713 ** Extend the buffer prior to deflate call if a reasonable amount
1714 ** of output buffer space is not available.
1716 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1717 if ( buff->zctrl.avail_out <= min_accept ) {
1718 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1722 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1723 if ( z_err != Z_OK ) {
1725 xmlStrPrintf(msg, 500,
1726 "xmlZMemBuffAppend: %s %d %s - %d",
1727 "Compression error while appending",
1728 len, "bytes to buffer. ZLIB error", z_err );
1729 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1734 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1740 * xmlZMemBuffGetContent
1741 * @buff: Compressed memory content buffer
1742 * @data_ref: Pointer reference to point to compressed content
1744 * Flushes the compression buffers, appends gzip file trailers and
1745 * returns the compressed content and length of the compressed data.
1746 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1748 * Returns the length of the compressed data or -1 on error.
1751 xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1756 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1759 /* Need to loop until compression output buffers are flushed */
1763 z_err = deflate( &buff->zctrl, Z_FINISH );
1764 if ( z_err == Z_OK ) {
1765 /* In this case Z_OK means more buffer space needed */
1767 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1771 while ( z_err == Z_OK );
1773 /* If the compression state is not Z_STREAM_END, some error occurred */
1775 if ( z_err == Z_STREAM_END ) {
1777 /* Need to append the gzip data trailer */
1779 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1780 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1785 ** For whatever reason, the CRC and length data are pushed out
1786 ** in reverse byte order. So a memcpy can't be used here.
1789 append_reverse_ulong( buff, buff->crc );
1790 append_reverse_ulong( buff, buff->zctrl.total_in );
1792 zlgth = buff->zctrl.next_out - buff->zbuff;
1793 *data_ref = (char *)buff->zbuff;
1798 xmlStrPrintf(msg, 500,
1799 "xmlZMemBuffGetContent: %s - %d\n",
1800 "Error flushing zlib buffers. Error code", z_err );
1801 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1806 #endif /* LIBXML_OUTPUT_ENABLED */
1807 #endif /* HAVE_ZLIB_H */
1809 #ifdef LIBXML_OUTPUT_ENABLED
1811 * xmlFreeHTTPWriteCtxt
1812 * @ctxt: Context to cleanup
1814 * Free allocated memory and reclaim system resources.
1819 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1821 if ( ctxt->uri != NULL )
1822 xmlFree( ctxt->uri );
1824 if ( ctxt->doc_buff != NULL ) {
1827 if ( ctxt->compression > 0 ) {
1828 xmlFreeZMemBuff( ctxt->doc_buff );
1833 xmlOutputBufferClose( ctxt->doc_buff );
1840 #endif /* LIBXML_OUTPUT_ENABLED */
1845 * @filename: the URI for matching
1847 * check if the URI matches an HTTP one
1849 * Returns 1 if matches, 0 otherwise
1852 xmlIOHTTPMatch (const char *filename) {
1853 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
1860 * @filename: the URI for matching
1862 * open an HTTP I/O channel
1864 * Returns an I/O context or NULL in case of error
1867 xmlIOHTTPOpen (const char *filename) {
1868 return(xmlNanoHTTPOpen(filename, NULL));
1871 #ifdef LIBXML_OUTPUT_ENABLED
1874 * @post_uri: The destination URI for the document
1875 * @compression: The compression desired for the document.
1877 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1878 * request. Non-static as is called from the output buffer creation routine.
1880 * Returns an I/O context or NULL in case of error.
1884 xmlIOHTTPOpenW(const char *post_uri, int compression ATTRIBUTE_UNUSED)
1887 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
1889 if (post_uri == NULL)
1892 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1894 xmlIOErrMemory("creating HTTP output context");
1898 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
1900 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1901 if (ctxt->uri == NULL) {
1902 xmlIOErrMemory("copying URI");
1903 xmlFreeHTTPWriteCtxt(ctxt);
1908 * ** Since the document length is required for an HTTP post,
1909 * ** need to put the document into a buffer. A memory buffer
1910 * ** is being used to avoid pushing the data to disk and back.
1914 if ((compression > 0) && (compression <= 9)) {
1916 ctxt->compression = compression;
1917 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1921 /* Any character conversions should have been done before this */
1923 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
1926 if (ctxt->doc_buff == NULL) {
1927 xmlFreeHTTPWriteCtxt(ctxt);
1933 #endif /* LIBXML_OUTPUT_ENABLED */
1935 #ifdef LIBXML_OUTPUT_ENABLED
1937 * xmlIOHTTPDfltOpenW
1938 * @post_uri: The destination URI for this document.
1940 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1941 * HTTP post command. This function should generally not be used as
1942 * the open callback is short circuited in xmlOutputBufferCreateFile.
1944 * Returns a pointer to the new IO context.
1947 xmlIOHTTPDfltOpenW( const char * post_uri ) {
1948 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1950 #endif /* LIBXML_OUTPUT_ENABLED */
1954 * @context: the I/O context
1955 * @buffer: where to drop data
1956 * @len: number of bytes to write
1958 * Read @len bytes to @buffer from the I/O channel.
1960 * Returns the number of bytes written
1963 xmlIOHTTPRead(void * context, char * buffer, int len) {
1964 if ((buffer == NULL) || (len < 0)) return(-1);
1965 return(xmlNanoHTTPRead(context, &buffer[0], len));
1968 #ifdef LIBXML_OUTPUT_ENABLED
1971 * @context: previously opened writing context
1972 * @buffer: data to output to temporary buffer
1973 * @len: bytes to output
1975 * Collect data from memory buffer into a temporary file for later
1978 * Returns number of bytes written.
1982 xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1984 xmlIOHTTPWriteCtxtPtr ctxt = context;
1986 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1991 /* Use gzwrite or fwrite as previously setup in the open call */
1994 if ( ctxt->compression > 0 )
1995 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1999 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
2003 xmlStrPrintf(msg, 500,
2004 "xmlIOHTTPWrite: %s\n%s '%s'.\n",
2005 "Error appending to internal buffer.",
2006 "Error sending document to URI",
2008 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2014 #endif /* LIBXML_OUTPUT_ENABLED */
2019 * @context: the I/O context
2021 * Close an HTTP I/O channel
2026 xmlIOHTTPClose (void * context) {
2027 xmlNanoHTTPClose(context);
2031 #ifdef LIBXML_OUTPUT_ENABLED
2033 * xmlIOHTTCloseWrite
2034 * @context: The I/O context
2035 * @http_mthd: The HTTP method to be used when sending the data
2037 * Close the transmit HTTP I/O channel and actually send the data.
2040 xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2044 int content_lgth = 0;
2045 xmlIOHTTPWriteCtxtPtr ctxt = context;
2047 char * http_content = NULL;
2048 char * content_encoding = NULL;
2049 char * content_type = (char *) "text/xml";
2050 void * http_ctxt = NULL;
2052 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2055 /* Retrieve the content from the appropriate buffer */
2059 if ( ctxt->compression > 0 ) {
2060 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2061 content_encoding = (char *) "Content-Encoding: gzip";
2066 /* Pull the data out of the memory output buffer */
2068 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
2069 http_content = (char *) xmlBufContent(dctxt->buffer);
2070 content_lgth = xmlBufUse(dctxt->buffer);
2073 if ( http_content == NULL ) {
2075 xmlStrPrintf(msg, 500,
2076 "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2077 "Error retrieving content.\nUnable to",
2078 http_mthd, "data to URI", ctxt->uri );
2079 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2084 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
2085 &content_type, content_encoding,
2088 if ( http_ctxt != NULL ) {
2090 /* If testing/debugging - dump reply with request content */
2092 FILE * tst_file = NULL;
2093 char buffer[ 4096 ];
2094 char * dump_name = NULL;
2097 xmlGenericError( xmlGenericErrorContext,
2098 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2099 http_mthd, ctxt->uri,
2100 xmlNanoHTTPReturnCode( http_ctxt ) );
2103 ** Since either content or reply may be gzipped,
2104 ** dump them to separate files instead of the
2105 ** standard error context.
2108 dump_name = tempnam( NULL, "lxml" );
2109 if ( dump_name != NULL ) {
2110 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
2112 tst_file = fopen( buffer, "wb" );
2113 if ( tst_file != NULL ) {
2114 xmlGenericError( xmlGenericErrorContext,
2115 "Transmitted content saved in file: %s\n", buffer );
2117 fwrite( http_content, sizeof( char ),
2118 content_lgth, tst_file );
2122 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
2123 tst_file = fopen( buffer, "wb" );
2124 if ( tst_file != NULL ) {
2125 xmlGenericError( xmlGenericErrorContext,
2126 "Reply content saved in file: %s\n", buffer );
2129 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2130 buffer, sizeof( buffer ) )) > 0 ) {
2132 fwrite( buffer, sizeof( char ), avail, tst_file );
2140 #endif /* DEBUG_HTTP */
2142 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2143 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2147 xmlStrPrintf(msg, 500,
2148 "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2149 http_mthd, content_lgth,
2150 "bytes to URI", ctxt->uri,
2151 "failed. HTTP return code:", http_rtn );
2152 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2155 xmlNanoHTTPClose( http_ctxt );
2156 xmlFree( content_type );
2160 /* Final cleanups */
2162 xmlFreeHTTPWriteCtxt( ctxt );
2164 return ( close_rc );
2170 * @context: The I/O context
2172 * Close the transmit HTTP I/O channel and actually send data using a PUT
2176 xmlIOHTTPClosePut( void * ctxt ) {
2177 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2182 * xmlIOHTTPClosePost
2184 * @context: The I/O context
2186 * Close the transmit HTTP I/O channel and actually send data using a POST
2190 xmlIOHTTPClosePost( void * ctxt ) {
2191 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2193 #endif /* LIBXML_OUTPUT_ENABLED */
2195 #endif /* LIBXML_HTTP_ENABLED */
2197 #ifdef LIBXML_FTP_ENABLED
2198 /************************************************************************
2200 * I/O for FTP file accesses *
2202 ************************************************************************/
2205 * @filename: the URI for matching
2207 * check if the URI matches an FTP one
2209 * Returns 1 if matches, 0 otherwise
2212 xmlIOFTPMatch (const char *filename) {
2213 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
2220 * @filename: the URI for matching
2222 * open an FTP I/O channel
2224 * Returns an I/O context or NULL in case of error
2227 xmlIOFTPOpen (const char *filename) {
2228 return(xmlNanoFTPOpen(filename));
2233 * @context: the I/O context
2234 * @buffer: where to drop data
2235 * @len: number of bytes to write
2237 * Read @len bytes to @buffer from the I/O channel.
2239 * Returns the number of bytes written
2242 xmlIOFTPRead(void * context, char * buffer, int len) {
2243 if ((buffer == NULL) || (len < 0)) return(-1);
2244 return(xmlNanoFTPRead(context, &buffer[0], len));
2249 * @context: the I/O context
2251 * Close an FTP I/O channel
2256 xmlIOFTPClose (void * context) {
2257 return ( xmlNanoFTPClose(context) );
2259 #endif /* LIBXML_FTP_ENABLED */
2263 * xmlRegisterInputCallbacks:
2264 * @matchFunc: the xmlInputMatchCallback
2265 * @openFunc: the xmlInputOpenCallback
2266 * @readFunc: the xmlInputReadCallback
2267 * @closeFunc: the xmlInputCloseCallback
2269 * Register a new set of I/O callback for handling parser input.
2271 * Returns the registered handler number or -1 in case of error
2274 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2275 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2276 xmlInputCloseCallback closeFunc) {
2277 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2280 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2281 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2282 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2283 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
2284 xmlInputCallbackInitialized = 1;
2285 return(xmlInputCallbackNr++);
2288 #ifdef LIBXML_OUTPUT_ENABLED
2290 * xmlRegisterOutputCallbacks:
2291 * @matchFunc: the xmlOutputMatchCallback
2292 * @openFunc: the xmlOutputOpenCallback
2293 * @writeFunc: the xmlOutputWriteCallback
2294 * @closeFunc: the xmlOutputCloseCallback
2296 * Register a new set of I/O callback for handling output.
2298 * Returns the registered handler number or -1 in case of error
2301 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2302 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2303 xmlOutputCloseCallback closeFunc) {
2304 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
2307 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2308 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2309 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2310 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
2311 xmlOutputCallbackInitialized = 1;
2312 return(xmlOutputCallbackNr++);
2314 #endif /* LIBXML_OUTPUT_ENABLED */
2317 * xmlRegisterDefaultInputCallbacks:
2319 * Registers the default compiled-in I/O handlers.
2322 xmlRegisterDefaultInputCallbacks(void) {
2323 if (xmlInputCallbackInitialized)
2326 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2327 xmlInitPlatformSpecificIo();
2330 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2331 xmlFileRead, xmlFileClose);
2333 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2334 xmlGzfileRead, xmlGzfileClose);
2335 #endif /* HAVE_ZLIB_H */
2336 #ifdef LIBXML_LZMA_ENABLED
2337 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2338 xmlXzfileRead, xmlXzfileClose);
2339 #endif /* LIBXML_LZMA_ENABLED */
2341 #ifdef LIBXML_HTTP_ENABLED
2342 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2343 xmlIOHTTPRead, xmlIOHTTPClose);
2344 #endif /* LIBXML_HTTP_ENABLED */
2346 #ifdef LIBXML_FTP_ENABLED
2347 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2348 xmlIOFTPRead, xmlIOFTPClose);
2349 #endif /* LIBXML_FTP_ENABLED */
2350 xmlInputCallbackInitialized = 1;
2353 #ifdef LIBXML_OUTPUT_ENABLED
2355 * xmlRegisterDefaultOutputCallbacks:
2357 * Registers the default compiled-in I/O handlers.
2360 xmlRegisterDefaultOutputCallbacks (void) {
2361 if (xmlOutputCallbackInitialized)
2364 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2365 xmlInitPlatformSpecificIo();
2368 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2369 xmlFileWrite, xmlFileClose);
2371 #ifdef LIBXML_HTTP_ENABLED
2372 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2373 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2376 /*********************************
2377 No way a-priori to distinguish between gzipped files from
2378 uncompressed ones except opening if existing then closing
2379 and saving with same compression ratio ... a pain.
2382 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2383 xmlGzfileWrite, xmlGzfileClose);
2387 #ifdef LIBXML_FTP_ENABLED
2388 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2389 xmlIOFTPWrite, xmlIOFTPClose);
2391 **********************************/
2392 xmlOutputCallbackInitialized = 1;
2395 #ifdef LIBXML_HTTP_ENABLED
2397 * xmlRegisterHTTPPostCallbacks:
2399 * By default, libxml submits HTTP output requests using the "PUT" method.
2400 * Calling this method changes the HTTP output method to use the "POST"
2405 xmlRegisterHTTPPostCallbacks( void ) {
2407 /* Register defaults if not done previously */
2409 if ( xmlOutputCallbackInitialized == 0 )
2410 xmlRegisterDefaultOutputCallbacks( );
2412 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2413 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2417 #endif /* LIBXML_OUTPUT_ENABLED */
2420 * xmlAllocParserInputBuffer:
2421 * @enc: the charset encoding if known
2423 * Create a buffered parser input for progressive parsing
2425 * Returns the new parser input or NULL
2427 xmlParserInputBufferPtr
2428 xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2429 xmlParserInputBufferPtr ret;
2431 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2433 xmlIOErrMemory("creating input buffer");
2436 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
2437 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2438 if (ret->buffer == NULL) {
2442 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2443 ret->encoder = xmlGetCharEncodingHandler(enc);
2444 if (ret->encoder != NULL)
2445 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2448 ret->readcallback = NULL;
2449 ret->closecallback = NULL;
2450 ret->context = NULL;
2451 ret->compressed = -1;
2452 ret->rawconsumed = 0;
2457 #ifdef LIBXML_OUTPUT_ENABLED
2459 * xmlAllocOutputBuffer:
2460 * @encoder: the encoding converter or NULL
2462 * Create a buffered parser output
2464 * Returns the new parser output or NULL
2467 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2468 xmlOutputBufferPtr ret;
2470 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2472 xmlIOErrMemory("creating output buffer");
2475 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2476 ret->buffer = xmlBufCreate();
2477 if (ret->buffer == NULL) {
2482 /* try to avoid a performance problem with Windows realloc() */
2483 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2484 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2486 ret->encoder = encoder;
2487 if (encoder != NULL) {
2488 ret->conv = xmlBufCreateSize(4000);
2489 if (ret->conv == NULL) {
2495 * This call is designed to initiate the encoder state
2497 xmlCharEncOutput(ret, 1);
2500 ret->writecallback = NULL;
2501 ret->closecallback = NULL;
2502 ret->context = NULL;
2509 * xmlAllocOutputBufferInternal:
2510 * @encoder: the encoding converter or NULL
2512 * Create a buffered parser output
2514 * Returns the new parser output or NULL
2517 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2518 xmlOutputBufferPtr ret;
2520 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2522 xmlIOErrMemory("creating output buffer");
2525 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2526 ret->buffer = xmlBufCreate();
2527 if (ret->buffer == NULL) {
2534 * For conversion buffers we use the special IO handling
2536 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
2538 ret->encoder = encoder;
2539 if (encoder != NULL) {
2540 ret->conv = xmlBufCreateSize(4000);
2541 if (ret->conv == NULL) {
2547 * This call is designed to initiate the encoder state
2549 xmlCharEncOutput(ret, 1);
2552 ret->writecallback = NULL;
2553 ret->closecallback = NULL;
2554 ret->context = NULL;
2560 #endif /* LIBXML_OUTPUT_ENABLED */
2563 * xmlFreeParserInputBuffer:
2564 * @in: a buffered parser input
2566 * Free up the memory used by a buffered parser input
2569 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
2570 if (in == NULL) return;
2573 xmlBufFree(in->raw);
2576 if (in->encoder != NULL) {
2577 xmlCharEncCloseFunc(in->encoder);
2579 if (in->closecallback != NULL) {
2580 in->closecallback(in->context);
2582 if (in->buffer != NULL) {
2583 xmlBufFree(in->buffer);
2590 #ifdef LIBXML_OUTPUT_ENABLED
2592 * xmlOutputBufferClose:
2593 * @out: a buffered output
2595 * flushes and close the output I/O channel
2596 * and free up all the associated resources
2598 * Returns the number of byte written or -1 in case of error.
2601 xmlOutputBufferClose(xmlOutputBufferPtr out)
2608 if (out->writecallback != NULL)
2609 xmlOutputBufferFlush(out);
2610 if (out->closecallback != NULL) {
2611 err_rc = out->closecallback(out->context);
2613 written = out->written;
2615 xmlBufFree(out->conv);
2618 if (out->encoder != NULL) {
2619 xmlCharEncCloseFunc(out->encoder);
2621 if (out->buffer != NULL) {
2622 xmlBufFree(out->buffer);
2629 return ((err_rc == 0) ? written : err_rc);
2631 #endif /* LIBXML_OUTPUT_ENABLED */
2633 xmlParserInputBufferPtr
2634 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2635 xmlParserInputBufferPtr ret;
2637 void *context = NULL;
2639 if (xmlInputCallbackInitialized == 0)
2640 xmlRegisterDefaultInputCallbacks();
2642 if (URI == NULL) return(NULL);
2645 * Try to find one of the input accept method accepting that scheme
2646 * Go in reverse to give precedence to user defined handlers.
2648 if (context == NULL) {
2649 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2650 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2651 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
2652 context = xmlInputCallbackTable[i].opencallback(URI);
2653 if (context != NULL) {
2659 if (context == NULL) {
2664 * Allocate the Input buffer front-end.
2666 ret = xmlAllocParserInputBuffer(enc);
2668 ret->context = context;
2669 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2670 ret->closecallback = xmlInputCallbackTable[i].closecallback;
2672 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2673 (strcmp(URI, "-") != 0)) {
2674 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2675 ret->compressed = !gzdirect(context);
2677 if (((z_stream *)context)->avail_in > 4) {
2678 char *cptr, buff4[4];
2679 cptr = (char *) ((z_stream *)context)->next_in;
2680 if (gzread(context, buff4, 4) == 4) {
2681 if (strncmp(buff4, cptr, 4) == 0)
2682 ret->compressed = 0;
2684 ret->compressed = 1;
2691 #ifdef LIBXML_LZMA_ENABLED
2692 if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2693 (strcmp(URI, "-") != 0)) {
2694 ret->compressed = __libxml2_xzcompressed(context);
2699 xmlInputCallbackTable[i].closecallback (context);
2705 * xmlParserInputBufferCreateFilename:
2706 * @URI: a C string containing the URI or filename
2707 * @enc: the charset encoding if known
2709 * Create a buffered parser input for the progressive parsing of a file
2710 * If filename is "-' then we use stdin as the input.
2711 * Automatic support for ZLIB/Compress compressed document is provided
2712 * by default if found at compile-time.
2713 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2715 * Returns the new parser input or NULL
2717 xmlParserInputBufferPtr
2718 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2719 if ((xmlParserInputBufferCreateFilenameValue)) {
2720 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2722 return __xmlParserInputBufferCreateFilename(URI, enc);
2725 #ifdef LIBXML_OUTPUT_ENABLED
2727 __xmlOutputBufferCreateFilename(const char *URI,
2728 xmlCharEncodingHandlerPtr encoder,
2729 int compression ATTRIBUTE_UNUSED) {
2730 xmlOutputBufferPtr ret;
2733 void *context = NULL;
2734 char *unescaped = NULL;
2736 int is_file_uri = 1;
2739 if (xmlOutputCallbackInitialized == 0)
2740 xmlRegisterDefaultOutputCallbacks();
2742 if (URI == NULL) return(NULL);
2744 puri = xmlParseURI(URI);
2747 if ((puri->scheme != NULL) &&
2748 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2752 * try to limit the damages of the URI unescaping code.
2754 if ((puri->scheme == NULL) ||
2755 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2756 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2761 * Try to find one of the output accept method accepting that scheme
2762 * Go in reverse to give precedence to user defined handlers.
2763 * try with an unescaped version of the URI
2765 if (unescaped != NULL) {
2767 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2768 context = xmlGzfileOpenW(unescaped, compression);
2769 if (context != NULL) {
2770 ret = xmlAllocOutputBufferInternal(encoder);
2772 ret->context = context;
2773 ret->writecallback = xmlGzfileWrite;
2774 ret->closecallback = xmlGzfileClose;
2781 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2782 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2783 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2784 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2785 /* Need to pass compression parameter into HTTP open calls */
2786 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2787 context = xmlIOHTTPOpenW(unescaped, compression);
2790 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2791 if (context != NULL)
2799 * If this failed try with a non-escaped URI this may be a strange
2802 if (context == NULL) {
2804 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2805 context = xmlGzfileOpenW(URI, compression);
2806 if (context != NULL) {
2807 ret = xmlAllocOutputBufferInternal(encoder);
2809 ret->context = context;
2810 ret->writecallback = xmlGzfileWrite;
2811 ret->closecallback = xmlGzfileClose;
2817 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2818 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2819 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
2820 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2821 /* Need to pass compression parameter into HTTP open calls */
2822 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2823 context = xmlIOHTTPOpenW(URI, compression);
2826 context = xmlOutputCallbackTable[i].opencallback(URI);
2827 if (context != NULL)
2833 if (context == NULL) {
2838 * Allocate the Output buffer front-end.
2840 ret = xmlAllocOutputBufferInternal(encoder);
2842 ret->context = context;
2843 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2844 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2850 * xmlOutputBufferCreateFilename:
2851 * @URI: a C string containing the URI or filename
2852 * @encoder: the encoding converter or NULL
2853 * @compression: the compression ration (0 none, 9 max).
2855 * Create a buffered output for the progressive saving of a file
2856 * If filename is "-' then we use stdout as the output.
2857 * Automatic support for ZLIB/Compress compressed document is provided
2858 * by default if found at compile-time.
2859 * TODO: currently if compression is set, the library only support
2860 * writing to a local file.
2862 * Returns the new output or NULL
2865 xmlOutputBufferCreateFilename(const char *URI,
2866 xmlCharEncodingHandlerPtr encoder,
2867 int compression ATTRIBUTE_UNUSED) {
2868 if ((xmlOutputBufferCreateFilenameValue)) {
2869 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2871 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2873 #endif /* LIBXML_OUTPUT_ENABLED */
2876 * xmlParserInputBufferCreateFile:
2878 * @enc: the charset encoding if known
2880 * Create a buffered parser input for the progressive parsing of a FILE *
2883 * Returns the new parser input or NULL
2885 xmlParserInputBufferPtr
2886 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2887 xmlParserInputBufferPtr ret;
2889 if (xmlInputCallbackInitialized == 0)
2890 xmlRegisterDefaultInputCallbacks();
2892 if (file == NULL) return(NULL);
2894 ret = xmlAllocParserInputBuffer(enc);
2896 ret->context = file;
2897 ret->readcallback = xmlFileRead;
2898 ret->closecallback = xmlFileFlush;
2904 #ifdef LIBXML_OUTPUT_ENABLED
2906 * xmlOutputBufferCreateFile:
2908 * @encoder: the encoding converter or NULL
2910 * Create a buffered output for the progressive saving to a FILE *
2913 * Returns the new parser output or NULL
2916 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2917 xmlOutputBufferPtr ret;
2919 if (xmlOutputCallbackInitialized == 0)
2920 xmlRegisterDefaultOutputCallbacks();
2922 if (file == NULL) return(NULL);
2924 ret = xmlAllocOutputBufferInternal(encoder);
2926 ret->context = file;
2927 ret->writecallback = xmlFileWrite;
2928 ret->closecallback = xmlFileFlush;
2935 * xmlOutputBufferCreateBuffer:
2936 * @buffer: a xmlBufferPtr
2937 * @encoder: the encoding converter or NULL
2939 * Create a buffered output for the progressive saving to a xmlBuffer
2941 * Returns the new parser output or NULL
2944 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2945 xmlCharEncodingHandlerPtr encoder) {
2946 xmlOutputBufferPtr ret;
2948 if (buffer == NULL) return(NULL);
2950 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2952 (xmlOutputCloseCallback)
2953 NULL, (void *) buffer, encoder);
2959 * xmlOutputBufferGetContent:
2960 * @out: an xmlOutputBufferPtr
2962 * Gives a pointer to the data currently held in the output buffer
2964 * Returns a pointer to the data or NULL in case of error
2967 xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2968 if ((out == NULL) || (out->buffer == NULL))
2971 return(xmlBufContent(out->buffer));
2975 * xmlOutputBufferGetSize:
2976 * @out: an xmlOutputBufferPtr
2978 * Gives the length of the data currently held in the output buffer
2980 * Returns 0 in case or error or no data is held, the size otherwise
2983 xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2984 if ((out == NULL) || (out->buffer == NULL))
2987 return(xmlBufUse(out->buffer));
2991 #endif /* LIBXML_OUTPUT_ENABLED */
2994 * xmlParserInputBufferCreateFd:
2995 * @fd: a file descriptor number
2996 * @enc: the charset encoding if known
2998 * Create a buffered parser input for the progressive parsing for the input
2999 * from a file descriptor
3001 * Returns the new parser input or NULL
3003 xmlParserInputBufferPtr
3004 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
3005 xmlParserInputBufferPtr ret;
3007 if (fd < 0) return(NULL);
3009 ret = xmlAllocParserInputBuffer(enc);
3011 ret->context = (void *) (long) fd;
3012 ret->readcallback = xmlFdRead;
3013 ret->closecallback = xmlFdClose;
3020 * xmlParserInputBufferCreateMem:
3021 * @mem: the memory input
3022 * @size: the length of the memory block
3023 * @enc: the charset encoding if known
3025 * Create a buffered parser input for the progressive parsing for the input
3026 * from a memory area.
3028 * Returns the new parser input or NULL
3030 xmlParserInputBufferPtr
3031 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3032 xmlParserInputBufferPtr ret;
3035 if (size < 0) return(NULL);
3036 if (mem == NULL) return(NULL);
3038 ret = xmlAllocParserInputBuffer(enc);
3040 ret->context = (void *) mem;
3041 ret->readcallback = (xmlInputReadCallback) xmlNop;
3042 ret->closecallback = NULL;
3043 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
3054 * xmlParserInputBufferCreateStatic:
3055 * @mem: the memory input
3056 * @size: the length of the memory block
3057 * @enc: the charset encoding if known
3059 * Create a buffered parser input for the progressive parsing for the input
3060 * from an immutable memory area. This will not copy the memory area to
3061 * the buffer, but the memory is expected to be available until the end of
3062 * the parsing, this is useful for example when using mmap'ed file.
3064 * Returns the new parser input or NULL
3066 xmlParserInputBufferPtr
3067 xmlParserInputBufferCreateStatic(const char *mem, int size,
3068 xmlCharEncoding enc) {
3069 xmlParserInputBufferPtr ret;
3071 if (size < 0) return(NULL);
3072 if (mem == NULL) return(NULL);
3074 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3076 xmlIOErrMemory("creating input buffer");
3079 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
3080 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
3081 if (ret->buffer == NULL) {
3085 ret->encoder = xmlGetCharEncodingHandler(enc);
3086 if (ret->encoder != NULL)
3087 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
3090 ret->compressed = -1;
3091 ret->context = (void *) mem;
3092 ret->readcallback = NULL;
3093 ret->closecallback = NULL;
3098 #ifdef LIBXML_OUTPUT_ENABLED
3100 * xmlOutputBufferCreateFd:
3101 * @fd: a file descriptor number
3102 * @encoder: the encoding converter or NULL
3104 * Create a buffered output for the progressive saving
3105 * to a file descriptor
3107 * Returns the new parser output or NULL
3110 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3111 xmlOutputBufferPtr ret;
3113 if (fd < 0) return(NULL);
3115 ret = xmlAllocOutputBufferInternal(encoder);
3117 ret->context = (void *) (long) fd;
3118 ret->writecallback = xmlFdWrite;
3119 ret->closecallback = NULL;
3124 #endif /* LIBXML_OUTPUT_ENABLED */
3127 * xmlParserInputBufferCreateIO:
3128 * @ioread: an I/O read function
3129 * @ioclose: an I/O close function
3130 * @ioctx: an I/O handler
3131 * @enc: the charset encoding if known
3133 * Create a buffered parser input for the progressive parsing for the input
3134 * from an I/O handler
3136 * Returns the new parser input or NULL
3138 xmlParserInputBufferPtr
3139 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3140 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3141 xmlParserInputBufferPtr ret;
3143 if (ioread == NULL) return(NULL);
3145 ret = xmlAllocParserInputBuffer(enc);
3147 ret->context = (void *) ioctx;
3148 ret->readcallback = ioread;
3149 ret->closecallback = ioclose;
3155 #ifdef LIBXML_OUTPUT_ENABLED
3157 * xmlOutputBufferCreateIO:
3158 * @iowrite: an I/O write function
3159 * @ioclose: an I/O close function
3160 * @ioctx: an I/O handler
3161 * @encoder: the charset encoding if known
3163 * Create a buffered output for the progressive saving
3166 * Returns the new parser output or NULL
3169 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3170 xmlOutputCloseCallback ioclose, void *ioctx,
3171 xmlCharEncodingHandlerPtr encoder) {
3172 xmlOutputBufferPtr ret;
3174 if (iowrite == NULL) return(NULL);
3176 ret = xmlAllocOutputBufferInternal(encoder);
3178 ret->context = (void *) ioctx;
3179 ret->writecallback = iowrite;
3180 ret->closecallback = ioclose;
3185 #endif /* LIBXML_OUTPUT_ENABLED */
3188 * xmlParserInputBufferCreateFilenameDefault:
3189 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3191 * Registers a callback for URI input file handling
3193 * Returns the old value of the registration function
3195 xmlParserInputBufferCreateFilenameFunc
3196 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3198 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3200 old = __xmlParserInputBufferCreateFilename;
3203 xmlParserInputBufferCreateFilenameValue = func;
3208 * xmlOutputBufferCreateFilenameDefault:
3209 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3211 * Registers a callback for URI output file handling
3213 * Returns the old value of the registration function
3215 xmlOutputBufferCreateFilenameFunc
3216 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3218 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3219 #ifdef LIBXML_OUTPUT_ENABLED
3221 old = __xmlOutputBufferCreateFilename;
3224 xmlOutputBufferCreateFilenameValue = func;
3229 * xmlParserInputBufferPush:
3230 * @in: a buffered parser input
3231 * @len: the size in bytes of the array.
3232 * @buf: an char array
3234 * Push the content of the arry in the input buffer
3235 * This routine handle the I18N transcoding to internal UTF-8
3236 * This is used when operating the parser in progressive (push) mode.
3238 * Returns the number of chars read and stored in the buffer, or -1
3242 xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3243 int len, const char *buf) {
3247 if (len < 0) return(0);
3248 if ((in == NULL) || (in->error)) return(-1);
3249 if (in->encoder != NULL) {
3253 * Store the data in the incoming raw buffer
3255 if (in->raw == NULL) {
3256 in->raw = xmlBufCreate();
3258 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
3263 * convert as much as possible to the parser reading buffer.
3265 use = xmlBufUse(in->raw);
3266 nbchars = xmlCharEncInput(in, 1);
3268 xmlIOErr(XML_IO_ENCODER, NULL);
3269 in->error = XML_IO_ENCODER;
3272 in->rawconsumed += (use - xmlBufUse(in->raw));
3275 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
3280 xmlGenericError(xmlGenericErrorContext,
3281 "I/O: pushed %d chars, buffer %d/%d\n",
3282 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
3290 * When reading from an Input channel indicated end of file or error
3291 * don't reread from it again.
3294 endOfInput (void * context ATTRIBUTE_UNUSED,
3295 char * buffer ATTRIBUTE_UNUSED,
3296 int len ATTRIBUTE_UNUSED) {
3301 * xmlParserInputBufferGrow:
3302 * @in: a buffered parser input
3303 * @len: indicative value of the amount of chars to read
3305 * Grow up the content of the input buffer, the old data are preserved
3306 * This routine handle the I18N transcoding to internal UTF-8
3307 * This routine is used when operating the parser in normal (pull) mode
3309 * TODO: one should be able to remove one extra copy by copying directly
3310 * onto in->buffer or in->raw
3312 * Returns the number of chars read and stored in the buffer, or -1
3316 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3317 char *buffer = NULL;
3321 if ((in == NULL) || (in->error)) return(-1);
3322 if ((len <= MINLEN) && (len != 4))
3325 if (xmlBufAvail(in->buffer) <= 0) {
3326 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
3327 in->error = XML_IO_BUFFER_FULL;
3331 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3332 xmlIOErrMemory("growing input buffer");
3333 in->error = XML_ERR_NO_MEMORY;
3336 buffer = (char *)xmlBufEnd(in->buffer);
3339 * Call the read method for this I/O type.
3341 if (in->readcallback != NULL) {
3342 res = in->readcallback(in->context, &buffer[0], len);
3344 in->readcallback = endOfInput;
3346 xmlIOErr(XML_IO_NO_INPUT, NULL);
3347 in->error = XML_IO_NO_INPUT;
3355 * try to establish compressed status of input if not done already
3357 if (in->compressed == -1) {
3358 #ifdef LIBXML_LZMA_ENABLED
3359 if (in->readcallback == xmlXzfileRead)
3360 in->compressed = __libxml2_xzcompressed(in->context);
3365 if (in->encoder != NULL) {
3369 * Store the data in the incoming raw buffer
3371 if (in->raw == NULL) {
3372 in->raw = xmlBufCreate();
3374 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
3379 * convert as much as possible to the parser reading buffer.
3381 use = xmlBufUse(in->raw);
3382 nbchars = xmlCharEncInput(in, 1);
3384 xmlIOErr(XML_IO_ENCODER, NULL);
3385 in->error = XML_IO_ENCODER;
3388 in->rawconsumed += (use - xmlBufUse(in->raw));
3391 xmlBufAddLen(in->buffer, nbchars);
3394 xmlGenericError(xmlGenericErrorContext,
3395 "I/O: read %d chars, buffer %d\n",
3396 nbchars, xmlBufUse(in->buffer));
3402 * xmlParserInputBufferRead:
3403 * @in: a buffered parser input
3404 * @len: indicative value of the amount of chars to read
3406 * Refresh the content of the input buffer, the old data are considered
3408 * This routine handle the I18N transcoding to internal UTF-8
3410 * Returns the number of chars read and stored in the buffer, or -1
3414 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
3415 if ((in == NULL) || (in->error)) return(-1);
3416 if (in->readcallback != NULL)
3417 return(xmlParserInputBufferGrow(in, len));
3418 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
3424 #ifdef LIBXML_OUTPUT_ENABLED
3426 * xmlOutputBufferWrite:
3427 * @out: a buffered parser output
3428 * @len: the size in bytes of the array.
3429 * @buf: an char array
3431 * Write the content of the array in the output I/O buffer
3432 * This routine handle the I18N transcoding from internal UTF-8
3433 * The buffer is lossless, i.e. will store in case of partial
3434 * or delayed writes.
3436 * Returns the number of chars immediately written, or -1
3440 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3441 int nbchars = 0; /* number of chars to output to I/O */
3442 int ret; /* return from function call */
3443 int written = 0; /* number of char written to I/O so far */
3444 int chunk; /* number of byte curreent processed from buf */
3446 if ((out == NULL) || (out->error)) return(-1);
3447 if (len < 0) return(0);
3448 if (out->error) return(-1);
3452 if (chunk > 4 * MINLEN)
3456 * first handle encoding stuff.
3458 if (out->encoder != NULL) {
3460 * Store the data in the incoming raw buffer
3462 if (out->conv == NULL) {
3463 out->conv = xmlBufCreate();
3465 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3469 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
3473 * convert as much as possible to the parser reading buffer.
3475 ret = xmlCharEncOutput(out, 0);
3476 if ((ret < 0) && (ret != -3)) {
3477 xmlIOErr(XML_IO_ENCODER, NULL);
3478 out->error = XML_IO_ENCODER;
3481 nbchars = xmlBufUse(out->conv);
3483 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3486 nbchars = xmlBufUse(out->buffer);
3491 if ((nbchars < MINLEN) && (len <= 0))
3494 if (out->writecallback) {
3496 * second write the stuff to the I/O channel
3498 if (out->encoder != NULL) {
3499 ret = out->writecallback(out->context,
3500 (const char *)xmlBufContent(out->conv), nbchars);
3502 xmlBufShrink(out->conv, ret);
3504 ret = out->writecallback(out->context,
3505 (const char *)xmlBufContent(out->buffer), nbchars);
3507 xmlBufShrink(out->buffer, ret);
3510 xmlIOErr(XML_IO_WRITE, NULL);
3511 out->error = XML_IO_WRITE;
3514 out->written += ret;
3521 xmlGenericError(xmlGenericErrorContext,
3522 "I/O: wrote %d chars\n", written);
3529 * @out: a pointer to an array of bytes to store the result
3530 * @outlen: the length of @out
3531 * @in: a pointer to an array of unescaped UTF-8 bytes
3532 * @inlen: the length of @in
3534 * Take a block of UTF-8 chars in and escape them.
3535 * Returns 0 if success, or -1 otherwise
3536 * The value of @inlen after return is the number of octets consumed
3537 * if the return value is positive, else unpredictable.
3538 * The value of @outlen after return is the number of octets consumed.
3541 xmlEscapeContent(unsigned char* out, int *outlen,
3542 const xmlChar* in, int *inlen) {
3543 unsigned char* outstart = out;
3544 const unsigned char* base = in;
3545 unsigned char* outend = out + *outlen;
3546 const unsigned char* inend;
3548 inend = in + (*inlen);
3550 while ((in < inend) && (out < outend)) {
3552 if (outend - out < 4) break;
3557 } else if (*in == '>') {
3558 if (outend - out < 4) break;
3563 } else if (*in == '&') {
3564 if (outend - out < 5) break;
3570 } else if (*in == '\r') {
3571 if (outend - out < 5) break;
3578 *out++ = (unsigned char) *in;
3582 *outlen = out - outstart;
3588 * xmlOutputBufferWriteEscape:
3589 * @out: a buffered parser output
3590 * @str: a zero terminated UTF-8 string
3591 * @escaping: an optional escaping function (or NULL)
3593 * Write the content of the string in the output I/O buffer
3594 * This routine escapes the caracters and then handle the I18N
3595 * transcoding from internal UTF-8
3596 * The buffer is lossless, i.e. will store in case of partial
3597 * or delayed writes.
3599 * Returns the number of chars immediately written, or -1
3603 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3604 xmlCharEncodingOutputFunc escaping) {
3605 int nbchars = 0; /* number of chars to output to I/O */
3606 int ret; /* return from function call */
3607 int written = 0; /* number of char written to I/O so far */
3608 int oldwritten=0;/* loop guard */
3609 int chunk; /* number of byte currently processed from str */
3610 int len; /* number of bytes in str */
3611 int cons; /* byte from str consumed */
3613 if ((out == NULL) || (out->error) || (str == NULL) ||
3614 (out->buffer == NULL) ||
3615 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3617 len = strlen((const char *)str);
3618 if (len < 0) return(0);
3619 if (out->error) return(-1);
3620 if (escaping == NULL) escaping = xmlEscapeContent;
3623 oldwritten = written;
3626 * how many bytes to consume and how many bytes to store.
3629 chunk = xmlBufAvail(out->buffer) - 1;
3632 * make sure we have enough room to save first, if this is
3633 * not the case force a flush, but make sure we stay in the loop
3636 if (xmlBufGrow(out->buffer, 100) < 0)
3643 * first handle encoding stuff.
3645 if (out->encoder != NULL) {
3647 * Store the data in the incoming raw buffer
3649 if (out->conv == NULL) {
3650 out->conv = xmlBufCreate();
3652 ret = escaping(xmlBufEnd(out->buffer) ,
3653 &chunk, str, &cons);
3654 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3656 xmlBufAddLen(out->buffer, chunk);
3658 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
3662 * convert as much as possible to the output buffer.
3664 ret = xmlCharEncOutput(out, 0);
3665 if ((ret < 0) && (ret != -3)) {
3666 xmlIOErr(XML_IO_ENCODER, NULL);
3667 out->error = XML_IO_ENCODER;
3670 nbchars = xmlBufUse(out->conv);
3672 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
3673 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3675 xmlBufAddLen(out->buffer, chunk);
3676 nbchars = xmlBufUse(out->buffer);
3681 if ((nbchars < MINLEN) && (len <= 0))
3684 if (out->writecallback) {
3686 * second write the stuff to the I/O channel
3688 if (out->encoder != NULL) {
3689 ret = out->writecallback(out->context,
3690 (const char *)xmlBufContent(out->conv), nbchars);
3692 xmlBufShrink(out->conv, ret);
3694 ret = out->writecallback(out->context,
3695 (const char *)xmlBufContent(out->buffer), nbchars);
3697 xmlBufShrink(out->buffer, ret);
3700 xmlIOErr(XML_IO_WRITE, NULL);
3701 out->error = XML_IO_WRITE;
3704 out->written += ret;
3705 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3706 xmlBufGrow(out->buffer, MINLEN);
3709 } while ((len > 0) && (oldwritten != written));
3713 xmlGenericError(xmlGenericErrorContext,
3714 "I/O: wrote %d chars\n", written);
3720 * xmlOutputBufferWriteString:
3721 * @out: a buffered parser output
3722 * @str: a zero terminated C string
3724 * Write the content of the string in the output I/O buffer
3725 * This routine handle the I18N transcoding from internal UTF-8
3726 * The buffer is lossless, i.e. will store in case of partial
3727 * or delayed writes.
3729 * Returns the number of chars immediately written, or -1
3733 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3736 if ((out == NULL) || (out->error)) return(-1);
3742 return(xmlOutputBufferWrite(out, len, str));
3747 * xmlOutputBufferFlush:
3748 * @out: a buffered output
3750 * flushes the output I/O channel
3752 * Returns the number of byte written or -1 in case of error.
3755 xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3756 int nbchars = 0, ret = 0;
3758 if ((out == NULL) || (out->error)) return(-1);
3760 * first handle encoding stuff.
3762 if ((out->conv != NULL) && (out->encoder != NULL)) {
3764 * convert as much as possible to the parser output buffer.
3767 nbchars = xmlCharEncOutput(out, 0);
3769 xmlIOErr(XML_IO_ENCODER, NULL);
3770 out->error = XML_IO_ENCODER;
3777 * second flush the stuff to the I/O channel
3779 if ((out->conv != NULL) && (out->encoder != NULL) &&
3780 (out->writecallback != NULL)) {
3781 ret = out->writecallback(out->context,
3782 (const char *)xmlBufContent(out->conv),
3783 xmlBufUse(out->conv));
3785 xmlBufShrink(out->conv, ret);
3786 } else if (out->writecallback != NULL) {
3787 ret = out->writecallback(out->context,
3788 (const char *)xmlBufContent(out->buffer),
3789 xmlBufUse(out->buffer));
3791 xmlBufShrink(out->buffer, ret);
3794 xmlIOErr(XML_IO_FLUSH, NULL);
3795 out->error = XML_IO_FLUSH;
3798 out->written += ret;
3801 xmlGenericError(xmlGenericErrorContext,
3802 "I/O: flushed %d chars\n", ret);
3806 #endif /* LIBXML_OUTPUT_ENABLED */
3809 * xmlParserGetDirectory:
3810 * @filename: the path to a file
3812 * lookup the directory for that file
3814 * Returns a new allocated string containing the directory, or NULL.
3817 xmlParserGetDirectory(const char *filename) {
3822 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3826 if (xmlInputCallbackInitialized == 0)
3827 xmlRegisterDefaultInputCallbacks();
3829 if (filename == NULL) return(NULL);
3831 #if defined(WIN32) && !defined(__CYGWIN__)
3832 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3834 # define IS_XMLPGD_SEP(ch) (ch=='/')
3837 strncpy(dir, filename, 1023);
3839 cur = &dir[strlen(dir)];
3841 if (IS_XMLPGD_SEP(*cur)) break;
3844 if (IS_XMLPGD_SEP(*cur)) {
3845 if (cur == dir) dir[1] = 0;
3847 ret = xmlMemStrdup(dir);
3849 if (getcwd(dir, 1024) != NULL) {
3851 ret = xmlMemStrdup(dir);
3855 #undef IS_XMLPGD_SEP
3858 /****************************************************************
3860 * External entities loading *
3862 ****************************************************************/
3865 * xmlCheckHTTPInput:
3866 * @ctxt: an XML parser context
3867 * @ret: an XML parser input
3869 * Check an input in case it was created from an HTTP stream, in that
3870 * case it will handle encoding and update of the base URL in case of
3871 * redirection. It also checks for HTTP errors in which case the input
3872 * is cleanly freed up and an appropriate error is raised in context
3874 * Returns the input or NULL in case of HTTP error.
3877 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3878 #ifdef LIBXML_HTTP_ENABLED
3879 if ((ret != NULL) && (ret->buf != NULL) &&
3880 (ret->buf->readcallback == xmlIOHTTPRead) &&
3881 (ret->buf->context != NULL)) {
3882 const char *encoding;
3887 code = xmlNanoHTTPReturnCode(ret->buf->context);
3890 if (ret->filename != NULL)
3891 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
3892 (const char *) ret->filename);
3894 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
3895 xmlFreeInputStream(ret);
3899 mime = xmlNanoHTTPMimeType(ret->buf->context);
3900 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3901 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3902 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3903 if (encoding != NULL) {
3904 xmlCharEncodingHandlerPtr handler;
3906 handler = xmlFindCharEncodingHandler(encoding);
3907 if (handler != NULL) {
3908 xmlSwitchInputEncoding(ctxt, ret, handler);
3910 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3911 "Unknown encoding %s",
3912 BAD_CAST encoding, NULL);
3914 if (ret->encoding == NULL)
3915 ret->encoding = xmlStrdup(BAD_CAST encoding);
3918 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3921 redir = xmlNanoHTTPRedir(ret->buf->context);
3922 if (redir != NULL) {
3923 if (ret->filename != NULL)
3924 xmlFree((xmlChar *) ret->filename);
3925 if (ret->directory != NULL) {
3926 xmlFree((xmlChar *) ret->directory);
3927 ret->directory = NULL;
3930 (char *) xmlStrdup((const xmlChar *) redir);
3938 static int xmlNoNetExists(const char *URL) {
3944 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
3945 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3950 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
3951 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3959 return xmlCheckFilename(path);
3962 #ifdef LIBXML_CATALOG_ENABLED
3965 * xmlResolveResourceFromCatalog:
3966 * @URL: the URL for the entity to load
3967 * @ID: the System ID for the entity to load
3968 * @ctxt: the context in which the entity is called or NULL
3970 * Resolves the URL and ID against the appropriate catalog.
3971 * This function is used by xmlDefaultExternalEntityLoader and
3972 * xmlNoNetExternalEntityLoader.
3974 * Returns a new allocated URL, or NULL.
3977 xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3978 xmlParserCtxtPtr ctxt) {
3979 xmlChar *resource = NULL;
3980 xmlCatalogAllow pref;
3983 * If the resource doesn't exists as a file,
3984 * try to load it from the resource pointed in the catalogs
3986 pref = xmlCatalogGetDefaults();
3988 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3992 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3993 ((pref == XML_CATA_ALLOW_ALL) ||
3994 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3995 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3996 (const xmlChar *)ID,
3997 (const xmlChar *)URL);
4000 * Try a global lookup
4002 if ((resource == NULL) &&
4003 ((pref == XML_CATA_ALLOW_ALL) ||
4004 (pref == XML_CATA_ALLOW_GLOBAL))) {
4005 resource = xmlCatalogResolve((const xmlChar *)ID,
4006 (const xmlChar *)URL);
4008 if ((resource == NULL) && (URL != NULL))
4009 resource = xmlStrdup((const xmlChar *) URL);
4012 * TODO: do an URI lookup on the reference
4014 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
4015 xmlChar *tmp = NULL;
4017 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
4018 ((pref == XML_CATA_ALLOW_ALL) ||
4019 (pref == XML_CATA_ALLOW_DOCUMENT))) {
4020 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
4022 if ((tmp == NULL) &&
4023 ((pref == XML_CATA_ALLOW_ALL) ||
4024 (pref == XML_CATA_ALLOW_GLOBAL))) {
4025 tmp = xmlCatalogResolveURI(resource);
4041 * xmlDefaultExternalEntityLoader:
4042 * @URL: the URL for the entity to load
4043 * @ID: the System ID for the entity to load
4044 * @ctxt: the context in which the entity is called or NULL
4046 * By default we don't load external entitites, yet.
4048 * Returns a new allocated xmlParserInputPtr, or NULL.
4050 static xmlParserInputPtr
4051 xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
4052 xmlParserCtxtPtr ctxt)
4054 xmlParserInputPtr ret = NULL;
4055 xmlChar *resource = NULL;
4057 #ifdef DEBUG_EXTERNAL_ENTITIES
4058 xmlGenericError(xmlGenericErrorContext,
4059 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
4061 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4062 int options = ctxt->options;
4064 ctxt->options -= XML_PARSE_NONET;
4065 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4066 ctxt->options = options;
4069 #ifdef LIBXML_CATALOG_ENABLED
4070 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4073 if (resource == NULL)
4074 resource = (xmlChar *) URL;
4076 if (resource == NULL) {
4079 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
4082 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
4083 if ((resource != NULL) && (resource != (xmlChar *) URL))
4088 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4089 xmlDefaultExternalEntityLoader;
4092 * xmlSetExternalEntityLoader:
4093 * @f: the new entity resolver function
4095 * Changes the defaultexternal entity resolver function for the application
4098 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4099 xmlCurrentExternalEntityLoader = f;
4103 * xmlGetExternalEntityLoader:
4105 * Get the default external entity resolver function for the application
4107 * Returns the xmlExternalEntityLoader function pointer
4109 xmlExternalEntityLoader
4110 xmlGetExternalEntityLoader(void) {
4111 return(xmlCurrentExternalEntityLoader);
4115 * xmlLoadExternalEntity:
4116 * @URL: the URL for the entity to load
4117 * @ID: the Public ID for the entity to load
4118 * @ctxt: the context in which the entity is called or NULL
4120 * Load an external entity, note that the use of this function for
4121 * unparsed entities may generate problems
4123 * Returns the xmlParserInputPtr or NULL
4126 xmlLoadExternalEntity(const char *URL, const char *ID,
4127 xmlParserCtxtPtr ctxt) {
4128 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
4129 char *canonicFilename;
4130 xmlParserInputPtr ret;
4132 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4133 if (canonicFilename == NULL) {
4134 xmlIOErrMemory("building canonical path\n");
4138 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4139 xmlFree(canonicFilename);
4142 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4145 /************************************************************************
4147 * Disabling Network access *
4149 ************************************************************************/
4152 * xmlNoNetExternalEntityLoader:
4153 * @URL: the URL for the entity to load
4154 * @ID: the System ID for the entity to load
4155 * @ctxt: the context in which the entity is called or NULL
4157 * A specific entity loader disabling network accesses, though still
4158 * allowing local catalog accesses for resolution.
4160 * Returns a new allocated xmlParserInputPtr, or NULL.
4163 xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4164 xmlParserCtxtPtr ctxt) {
4165 xmlParserInputPtr input = NULL;
4166 xmlChar *resource = NULL;
4168 #ifdef LIBXML_CATALOG_ENABLED
4169 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4172 if (resource == NULL)
4173 resource = (xmlChar *) URL;
4175 if (resource != NULL) {
4176 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4177 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
4178 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
4179 if (resource != (xmlChar *) URL)
4184 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4185 if (resource != (xmlChar *) URL)
4190 #define bottom_xmlIO
4191 #include "elfgcchack.h"