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