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