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