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