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