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 *
__xmlIOWin32UTF8ToWChar(const char * u8String)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
xmlIOErrMemory(const char * extra)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
__xmlIOErr(int domain,int code,const char * extra)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
xmlIOErr(int code,const char * extra)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
__xmlLoaderErr(void * ctx,const char * msg,const char * filename)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 *
xmlNormalizeWindowsPath(const xmlChar * path)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
xmlCleanupInputCallbacks(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
xmlPopInputCallbacks(void)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
xmlCleanupOutputCallbacks(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*
xmlWrapOpenUtf8(const char * path,int mode)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
xmlWrapGzOpenUtf8(const char * path,const char * mode)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
xmlWrapStatUtf8(const char * path,struct stat * info)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*
xmlWrapOpenNative(const char * path,int mode)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
xmlWrapStatNative(const char * path,struct stat * info)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
xmlInitPlatformSpecificIo(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
xmlCheckFilename(const char * path)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
xmlNop(void)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
xmlFdRead(void * context,char * buffer,int len)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
xmlFdWrite(void * context,const char * buffer,int len)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
xmlFdClose(void * context)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
xmlFileMatch(const char * filename ATTRIBUTE_UNUSED)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 *
xmlFileOpen_real(const char * filename)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 *
xmlFileOpen(const char * filename)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 *
xmlFileOpenW(const char * filename)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
xmlFileRead(void * context,char * buffer,int len)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
xmlFileWrite(void * context,const char * buffer,int len)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
xmlFileClose(void * context)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
xmlFileFlush(void * context)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
xmlBufferWrite(void * context,const char * buffer,int len)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
xmlGzfileMatch(const char * filename ATTRIBUTE_UNUSED)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 *
xmlGzfileOpen_real(const char * filename)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 *
xmlGzfileOpen(const char * filename)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 *
xmlGzfileOpenW(const char * filename,int compression)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
xmlGzfileRead(void * context,char * buffer,int len)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
xmlGzfileWrite(void * context,const char * buffer,int len)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
xmlGzfileClose(void * context)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
append_reverse_ulong(xmlZMemBuff * buff,unsigned long data)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
xmlFreeZMemBuff(xmlZMemBuffPtr buff)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 *
xmlCreateZMemBuff(int compression)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
xmlZMemBuffExtend(xmlZMemBuffPtr buff,size_t ext_amt)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
xmlZMemBuffAppend(xmlZMemBuffPtr buff,const char * src,int len)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
xmlZMemBuffGetContent(xmlZMemBuffPtr buff,char ** data_ref)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
xmlFreeHTTPWriteCtxt(xmlIOHTTPWriteCtxtPtr ctxt)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
xmlIOHTTPMatch(const char * filename)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 *
xmlIOHTTPOpen(const char * filename)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 *
xmlIOHTTPOpenW(const char * post_uri,int compression)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 *
xmlIOHTTPDfltOpenW(const char * post_uri)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
xmlIOHTTPRead(void * context,char * buffer,int len)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
xmlIOHTTPWrite(void * context,const char * buffer,int len)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
xmlIOHTTPClose(void * context)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
xmlIOHTTPCloseWrite(void * context,const char * http_mthd)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
xmlIOHTTPClosePut(void * ctxt)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
xmlIOHTTPClosePost(void * ctxt)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
xmlIOFTPMatch(const char * filename)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 *
xmlIOFTPOpen(const char * filename)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
xmlIOFTPRead(void * context,char * buffer,int len)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
xmlIOFTPClose(void * context)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
xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,xmlInputOpenCallback openFunc,xmlInputReadCallback readFunc,xmlInputCloseCallback closeFunc)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
xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,xmlOutputOpenCallback openFunc,xmlOutputWriteCallback writeFunc,xmlOutputCloseCallback closeFunc)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
xmlRegisterDefaultInputCallbacks(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
xmlRegisterDefaultOutputCallbacks(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
xmlRegisterHTTPPostCallbacks(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
xmlAllocParserInputBuffer(xmlCharEncoding enc)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
xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder)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
xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder)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
xmlFreeParserInputBuffer(xmlParserInputBufferPtr in)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
xmlOutputBufferClose(xmlOutputBufferPtr out)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
__xmlParserInputBufferCreateFilename(const char * URI,xmlCharEncoding enc)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
xmlParserInputBufferCreateFilename(const char * URI,xmlCharEncoding enc)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
__xmlOutputBufferCreateFilename(const char * URI,xmlCharEncodingHandlerPtr encoder,int compression ATTRIBUTE_UNUSED)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
xmlOutputBufferCreateFilename(const char * URI,xmlCharEncodingHandlerPtr encoder,int compression ATTRIBUTE_UNUSED)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
xmlParserInputBufferCreateFile(FILE * file,xmlCharEncoding enc)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
xmlOutputBufferCreateFile(FILE * file,xmlCharEncodingHandlerPtr encoder)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
xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,xmlCharEncodingHandlerPtr encoder)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
xmlParserInputBufferCreateFd(int fd,xmlCharEncoding enc)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
xmlParserInputBufferCreateMem(const char * mem,int size,xmlCharEncoding enc)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
xmlParserInputBufferCreateStatic(const char * mem,int size,xmlCharEncoding enc)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
xmlOutputBufferCreateFd(int fd,xmlCharEncodingHandlerPtr encoder)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
xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx,xmlCharEncoding enc)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
xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,xmlOutputCloseCallback ioclose,void * ioctx,xmlCharEncodingHandlerPtr encoder)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
xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)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
xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)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
xmlParserInputBufferPush(xmlParserInputBufferPtr in,int len,const char * buf)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
endOfInput(void * context ATTRIBUTE_UNUSED,char * buffer ATTRIBUTE_UNUSED,int len ATTRIBUTE_UNUSED)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
xmlParserInputBufferGrow(xmlParserInputBufferPtr in,int len)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
xmlParserInputBufferRead(xmlParserInputBufferPtr in,int len)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
xmlOutputBufferWrite(xmlOutputBufferPtr out,int len,const char * buf)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
xmlEscapeContent(unsigned char * out,int * outlen,const xmlChar * in,int * inlen)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
xmlOutputBufferWriteEscape(xmlOutputBufferPtr out,const xmlChar * str,xmlCharEncodingOutputFunc escaping)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
xmlOutputBufferWriteString(xmlOutputBufferPtr out,const char * str)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
xmlOutputBufferFlush(xmlOutputBufferPtr out)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 *
xmlParserGetDirectory(const char * filename)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
xmlCheckHTTPInput(xmlParserCtxtPtr ctxt,xmlParserInputPtr ret)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 
xmlNoNetExists(const char * URL)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 *
xmlResolveResourceFromCatalog(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)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
xmlDefaultExternalEntityLoader(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)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
xmlSetExternalEntityLoader(xmlExternalEntityLoader f)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
xmlGetExternalEntityLoader(void)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
xmlLoadExternalEntity(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)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
xmlNoNetExternalEntityLoader(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)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"
3995