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