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