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