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