• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xmlIO.c : implementation of the I/O interfaces used by the parser
3  *
4  * See Copyright for the status of this software.
5  *
6  * daniel@veillard.com
7  *
8  * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9  */
10 
11 #define IN_LIBXML
12 #include "libxml.h"
13 
14 #include <string.h>
15 #include <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     "address in use",		/* EADDRINUSE */
189     "already in use",		/* EALREADY */
190     "unknown address family",	/* 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             xmlBufFree(ret->buffer);
2387 	    xmlFree(ret);
2388 	    return(NULL);
2389 	}
2390 
2391 	/*
2392 	 * This call is designed to initiate the encoder state
2393 	 */
2394 	xmlCharEncOutput(ret, 1);
2395     } else
2396         ret->conv = NULL;
2397     ret->writecallback = NULL;
2398     ret->closecallback = NULL;
2399     ret->context = NULL;
2400     ret->written = 0;
2401 
2402     return(ret);
2403 }
2404 
2405 /**
2406  * xmlAllocOutputBufferInternal:
2407  * @encoder:  the encoding converter or NULL
2408  *
2409  * Create a buffered parser output
2410  *
2411  * Returns the new parser output or NULL
2412  */
2413 xmlOutputBufferPtr
xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder)2414 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2415     xmlOutputBufferPtr ret;
2416 
2417     ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2418     if (ret == NULL) {
2419 	xmlIOErrMemory("creating output buffer");
2420 	return(NULL);
2421     }
2422     memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2423     ret->buffer = xmlBufCreate();
2424     if (ret->buffer == NULL) {
2425         xmlFree(ret);
2426 	return(NULL);
2427     }
2428 
2429 
2430     /*
2431      * For conversion buffers we use the special IO handling
2432      */
2433     xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
2434 
2435     ret->encoder = encoder;
2436     if (encoder != NULL) {
2437         ret->conv = xmlBufCreateSize(4000);
2438 	if (ret->conv == NULL) {
2439             xmlBufFree(ret->buffer);
2440 	    xmlFree(ret);
2441 	    return(NULL);
2442 	}
2443 
2444 	/*
2445 	 * This call is designed to initiate the encoder state
2446 	 */
2447         xmlCharEncOutput(ret, 1);
2448     } else
2449         ret->conv = NULL;
2450     ret->writecallback = NULL;
2451     ret->closecallback = NULL;
2452     ret->context = NULL;
2453     ret->written = 0;
2454 
2455     return(ret);
2456 }
2457 
2458 #endif /* LIBXML_OUTPUT_ENABLED */
2459 
2460 /**
2461  * xmlFreeParserInputBuffer:
2462  * @in:  a buffered parser input
2463  *
2464  * Free up the memory used by a buffered parser input
2465  */
2466 void
xmlFreeParserInputBuffer(xmlParserInputBufferPtr in)2467 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
2468     if (in == NULL) return;
2469 
2470     if (in->raw) {
2471         xmlBufFree(in->raw);
2472 	in->raw = NULL;
2473     }
2474     if (in->encoder != NULL) {
2475         xmlCharEncCloseFunc(in->encoder);
2476     }
2477     if (in->closecallback != NULL) {
2478 	in->closecallback(in->context);
2479     }
2480     if (in->buffer != NULL) {
2481         xmlBufFree(in->buffer);
2482 	in->buffer = NULL;
2483     }
2484 
2485     xmlFree(in);
2486 }
2487 
2488 #ifdef LIBXML_OUTPUT_ENABLED
2489 /**
2490  * xmlOutputBufferClose:
2491  * @out:  a buffered output
2492  *
2493  * flushes and close the output I/O channel
2494  * and free up all the associated resources
2495  *
2496  * Returns the number of byte written or -1 in case of error.
2497  */
2498 int
xmlOutputBufferClose(xmlOutputBufferPtr out)2499 xmlOutputBufferClose(xmlOutputBufferPtr out)
2500 {
2501     int written;
2502     int err_rc = 0;
2503 
2504     if (out == NULL)
2505         return (-1);
2506     if (out->writecallback != NULL)
2507         xmlOutputBufferFlush(out);
2508     if (out->closecallback != NULL) {
2509         err_rc = out->closecallback(out->context);
2510     }
2511     written = out->written;
2512     if (out->conv) {
2513         xmlBufFree(out->conv);
2514         out->conv = NULL;
2515     }
2516     if (out->encoder != NULL) {
2517         xmlCharEncCloseFunc(out->encoder);
2518     }
2519     if (out->buffer != NULL) {
2520         xmlBufFree(out->buffer);
2521         out->buffer = NULL;
2522     }
2523 
2524     if (out->error)
2525         err_rc = -1;
2526     xmlFree(out);
2527     return ((err_rc == 0) ? written : err_rc);
2528 }
2529 #endif /* LIBXML_OUTPUT_ENABLED */
2530 
2531 xmlParserInputBufferPtr
__xmlParserInputBufferCreateFilename(const char * URI,xmlCharEncoding enc)2532 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2533     xmlParserInputBufferPtr ret;
2534     int i = 0;
2535     void *context = NULL;
2536 
2537     if (xmlInputCallbackInitialized == 0)
2538 	xmlRegisterDefaultInputCallbacks();
2539 
2540     if (URI == NULL) return(NULL);
2541 
2542     /*
2543      * Try to find one of the input accept method accepting that scheme
2544      * Go in reverse to give precedence to user defined handlers.
2545      */
2546     if (context == NULL) {
2547 	for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2548 	    if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2549 		(xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
2550 		context = xmlInputCallbackTable[i].opencallback(URI);
2551 		if (context != NULL) {
2552 		    break;
2553 		}
2554 	    }
2555 	}
2556     }
2557     if (context == NULL) {
2558 	return(NULL);
2559     }
2560 
2561     /*
2562      * Allocate the Input buffer front-end.
2563      */
2564     ret = xmlAllocParserInputBuffer(enc);
2565     if (ret != NULL) {
2566 	ret->context = context;
2567 	ret->readcallback = xmlInputCallbackTable[i].readcallback;
2568 	ret->closecallback = xmlInputCallbackTable[i].closecallback;
2569 #ifdef LIBXML_ZLIB_ENABLED
2570 	if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2571 		(strcmp(URI, "-") != 0)) {
2572 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2573             ret->compressed = !gzdirect(context);
2574 #else
2575 	    if (((z_stream *)context)->avail_in > 4) {
2576 	        char *cptr, buff4[4];
2577 		cptr = (char *) ((z_stream *)context)->next_in;
2578 		if (gzread(context, buff4, 4) == 4) {
2579 		    if (strncmp(buff4, cptr, 4) == 0)
2580 		        ret->compressed = 0;
2581 		    else
2582 		        ret->compressed = 1;
2583 		    gzrewind(context);
2584 		}
2585 	    }
2586 #endif
2587 	}
2588 #endif
2589 #ifdef LIBXML_LZMA_ENABLED
2590 	if ((xmlInputCallbackTable[i].opencallback == xmlXzfileOpen) &&
2591 		(strcmp(URI, "-") != 0)) {
2592             ret->compressed = __libxml2_xzcompressed(context);
2593 	}
2594 #endif
2595     }
2596     else
2597       xmlInputCallbackTable[i].closecallback (context);
2598 
2599     return(ret);
2600 }
2601 
2602 /**
2603  * xmlParserInputBufferCreateFilename:
2604  * @URI:  a C string containing the URI or filename
2605  * @enc:  the charset encoding if known
2606  *
2607  * Create a buffered parser input for the progressive parsing of a file
2608  * If filename is "-' then we use stdin as the input.
2609  * Automatic support for ZLIB/Compress compressed document is provided
2610  * by default if found at compile-time.
2611  * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2612  *
2613  * Returns the new parser input or NULL
2614  */
2615 xmlParserInputBufferPtr
xmlParserInputBufferCreateFilename(const char * URI,xmlCharEncoding enc)2616 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2617     if ((xmlParserInputBufferCreateFilenameValue)) {
2618 		return xmlParserInputBufferCreateFilenameValue(URI, enc);
2619 	}
2620 	return __xmlParserInputBufferCreateFilename(URI, enc);
2621 }
2622 
2623 #ifdef LIBXML_OUTPUT_ENABLED
2624 xmlOutputBufferPtr
__xmlOutputBufferCreateFilename(const char * URI,xmlCharEncodingHandlerPtr encoder,int compression ATTRIBUTE_UNUSED)2625 __xmlOutputBufferCreateFilename(const char *URI,
2626                               xmlCharEncodingHandlerPtr encoder,
2627                               int compression ATTRIBUTE_UNUSED) {
2628     xmlOutputBufferPtr ret;
2629     xmlURIPtr puri;
2630     int i = 0;
2631     void *context = NULL;
2632     char *unescaped = NULL;
2633 #ifdef LIBXML_ZLIB_ENABLED
2634     int is_file_uri = 1;
2635 #endif
2636 
2637     if (xmlOutputCallbackInitialized == 0)
2638 	xmlRegisterDefaultOutputCallbacks();
2639 
2640     if (URI == NULL) return(NULL);
2641 
2642     puri = xmlParseURI(URI);
2643     if (puri != NULL) {
2644 #ifdef LIBXML_ZLIB_ENABLED
2645         if ((puri->scheme != NULL) &&
2646 	    (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2647 	    is_file_uri = 0;
2648 #endif
2649 	/*
2650 	 * try to limit the damages of the URI unescaping code.
2651 	 */
2652 	if ((puri->scheme == NULL) ||
2653 	    (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2654 	    unescaped = xmlURIUnescapeString(URI, 0, NULL);
2655 	xmlFreeURI(puri);
2656     }
2657 
2658     /*
2659      * Try to find one of the output accept method accepting that scheme
2660      * Go in reverse to give precedence to user defined handlers.
2661      * try with an unescaped version of the URI
2662      */
2663     if (unescaped != NULL) {
2664 #ifdef LIBXML_ZLIB_ENABLED
2665 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2666 	    context = xmlGzfileOpenW(unescaped, compression);
2667 	    if (context != NULL) {
2668 		ret = xmlAllocOutputBufferInternal(encoder);
2669 		if (ret != NULL) {
2670 		    ret->context = context;
2671 		    ret->writecallback = xmlGzfileWrite;
2672 		    ret->closecallback = xmlGzfileClose;
2673 		}
2674 		xmlFree(unescaped);
2675 		return(ret);
2676 	    }
2677 	}
2678 #endif
2679 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2680 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2681 		(xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2682 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2683 		/*  Need to pass compression parameter into HTTP open calls  */
2684 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2685 		    context = xmlIOHTTPOpenW(unescaped, compression);
2686 		else
2687 #endif
2688 		    context = xmlOutputCallbackTable[i].opencallback(unescaped);
2689 		if (context != NULL)
2690 		    break;
2691 	    }
2692 	}
2693 	xmlFree(unescaped);
2694     }
2695 
2696     /*
2697      * If this failed try with a non-escaped URI this may be a strange
2698      * filename
2699      */
2700     if (context == NULL) {
2701 #ifdef LIBXML_ZLIB_ENABLED
2702 	if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2703 	    context = xmlGzfileOpenW(URI, compression);
2704 	    if (context != NULL) {
2705 		ret = xmlAllocOutputBufferInternal(encoder);
2706 		if (ret != NULL) {
2707 		    ret->context = context;
2708 		    ret->writecallback = xmlGzfileWrite;
2709 		    ret->closecallback = xmlGzfileClose;
2710 		}
2711 		return(ret);
2712 	    }
2713 	}
2714 #endif
2715 	for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2716 	    if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2717 		(xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
2718 #if defined(LIBXML_HTTP_ENABLED) && defined(LIBXML_ZLIB_ENABLED)
2719 		/*  Need to pass compression parameter into HTTP open calls  */
2720 		if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2721 		    context = xmlIOHTTPOpenW(URI, compression);
2722 		else
2723 #endif
2724 		    context = xmlOutputCallbackTable[i].opencallback(URI);
2725 		if (context != NULL)
2726 		    break;
2727 	    }
2728 	}
2729     }
2730 
2731     if (context == NULL) {
2732 	return(NULL);
2733     }
2734 
2735     /*
2736      * Allocate the Output buffer front-end.
2737      */
2738     ret = xmlAllocOutputBufferInternal(encoder);
2739     if (ret != NULL) {
2740 	ret->context = context;
2741 	ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2742 	ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2743     }
2744     return(ret);
2745 }
2746 
2747 /**
2748  * xmlOutputBufferCreateFilename:
2749  * @URI:  a C string containing the URI or filename
2750  * @encoder:  the encoding converter or NULL
2751  * @compression:  the compression ration (0 none, 9 max).
2752  *
2753  * Create a buffered  output for the progressive saving of a file
2754  * If filename is "-' then we use stdout as the output.
2755  * Automatic support for ZLIB/Compress compressed document is provided
2756  * by default if found at compile-time.
2757  * TODO: currently if compression is set, the library only support
2758  *       writing to a local file.
2759  *
2760  * Returns the new output or NULL
2761  */
2762 xmlOutputBufferPtr
xmlOutputBufferCreateFilename(const char * URI,xmlCharEncodingHandlerPtr encoder,int compression ATTRIBUTE_UNUSED)2763 xmlOutputBufferCreateFilename(const char *URI,
2764                               xmlCharEncodingHandlerPtr encoder,
2765                               int compression ATTRIBUTE_UNUSED) {
2766     if ((xmlOutputBufferCreateFilenameValue)) {
2767 		return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2768 	}
2769 	return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2770 }
2771 #endif /* LIBXML_OUTPUT_ENABLED */
2772 
2773 /**
2774  * xmlParserInputBufferCreateFile:
2775  * @file:  a FILE*
2776  * @enc:  the charset encoding if known
2777  *
2778  * Create a buffered parser input for the progressive parsing of a FILE *
2779  * buffered C I/O
2780  *
2781  * Returns the new parser input or NULL
2782  */
2783 xmlParserInputBufferPtr
xmlParserInputBufferCreateFile(FILE * file,xmlCharEncoding enc)2784 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2785     xmlParserInputBufferPtr ret;
2786 
2787     if (xmlInputCallbackInitialized == 0)
2788 	xmlRegisterDefaultInputCallbacks();
2789 
2790     if (file == NULL) return(NULL);
2791 
2792     ret = xmlAllocParserInputBuffer(enc);
2793     if (ret != NULL) {
2794         ret->context = file;
2795 	ret->readcallback = xmlFileRead;
2796 	ret->closecallback = xmlFileFlush;
2797     }
2798 
2799     return(ret);
2800 }
2801 
2802 #ifdef LIBXML_OUTPUT_ENABLED
2803 /**
2804  * xmlOutputBufferCreateFile:
2805  * @file:  a FILE*
2806  * @encoder:  the encoding converter or NULL
2807  *
2808  * Create a buffered output for the progressive saving to a FILE *
2809  * buffered C I/O
2810  *
2811  * Returns the new parser output or NULL
2812  */
2813 xmlOutputBufferPtr
xmlOutputBufferCreateFile(FILE * file,xmlCharEncodingHandlerPtr encoder)2814 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2815     xmlOutputBufferPtr ret;
2816 
2817     if (xmlOutputCallbackInitialized == 0)
2818 	xmlRegisterDefaultOutputCallbacks();
2819 
2820     if (file == NULL) return(NULL);
2821 
2822     ret = xmlAllocOutputBufferInternal(encoder);
2823     if (ret != NULL) {
2824         ret->context = file;
2825 	ret->writecallback = xmlFileWrite;
2826 	ret->closecallback = xmlFileFlush;
2827     }
2828 
2829     return(ret);
2830 }
2831 
2832 /**
2833  * xmlOutputBufferCreateBuffer:
2834  * @buffer:  a xmlBufferPtr
2835  * @encoder:  the encoding converter or NULL
2836  *
2837  * Create a buffered output for the progressive saving to a xmlBuffer
2838  *
2839  * Returns the new parser output or NULL
2840  */
2841 xmlOutputBufferPtr
xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,xmlCharEncodingHandlerPtr encoder)2842 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2843                             xmlCharEncodingHandlerPtr encoder) {
2844     xmlOutputBufferPtr ret;
2845 
2846     if (buffer == NULL) return(NULL);
2847 
2848     ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
2849                                   encoder);
2850 
2851     return(ret);
2852 }
2853 
2854 /**
2855  * xmlOutputBufferGetContent:
2856  * @out:  an xmlOutputBufferPtr
2857  *
2858  * Gives a pointer to the data currently held in the output buffer
2859  *
2860  * Returns a pointer to the data or NULL in case of error
2861  */
2862 const xmlChar *
xmlOutputBufferGetContent(xmlOutputBufferPtr out)2863 xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2864     if ((out == NULL) || (out->buffer == NULL))
2865         return(NULL);
2866 
2867     return(xmlBufContent(out->buffer));
2868 }
2869 
2870 /**
2871  * xmlOutputBufferGetSize:
2872  * @out:  an xmlOutputBufferPtr
2873  *
2874  * Gives the length of the data currently held in the output buffer
2875  *
2876  * Returns 0 in case or error or no data is held, the size otherwise
2877  */
2878 size_t
xmlOutputBufferGetSize(xmlOutputBufferPtr out)2879 xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2880     if ((out == NULL) || (out->buffer == NULL))
2881         return(0);
2882 
2883     return(xmlBufUse(out->buffer));
2884 }
2885 
2886 
2887 #endif /* LIBXML_OUTPUT_ENABLED */
2888 
2889 /**
2890  * xmlParserInputBufferCreateFd:
2891  * @fd:  a file descriptor number
2892  * @enc:  the charset encoding if known
2893  *
2894  * Create a buffered parser input for the progressive parsing for the input
2895  * from a file descriptor
2896  *
2897  * Returns the new parser input or NULL
2898  */
2899 xmlParserInputBufferPtr
xmlParserInputBufferCreateFd(int fd,xmlCharEncoding enc)2900 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2901     xmlParserInputBufferPtr ret;
2902 
2903     if (fd < 0) return(NULL);
2904 
2905     ret = xmlAllocParserInputBuffer(enc);
2906     if (ret != NULL) {
2907         ret->context = (void *) (ptrdiff_t) fd;
2908 	ret->readcallback = xmlFdRead;
2909 	ret->closecallback = xmlFdClose;
2910     }
2911 
2912     return(ret);
2913 }
2914 
2915 /**
2916  * xmlParserInputBufferCreateMem:
2917  * @mem:  the memory input
2918  * @size:  the length of the memory block
2919  * @enc:  the charset encoding if known
2920  *
2921  * Create a buffered parser input for the progressive parsing for the input
2922  * from a memory area.
2923  *
2924  * Returns the new parser input or NULL
2925  */
2926 xmlParserInputBufferPtr
xmlParserInputBufferCreateMem(const char * mem,int size,xmlCharEncoding enc)2927 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2928     xmlParserInputBufferPtr ret;
2929     int errcode;
2930 
2931     if (size < 0) return(NULL);
2932     if (mem == NULL) return(NULL);
2933 
2934     ret = xmlAllocParserInputBuffer(enc);
2935     if (ret != NULL) {
2936         ret->context = (void *) mem;
2937 	ret->readcallback = xmlInputReadCallbackNop;
2938 	ret->closecallback = NULL;
2939 	errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
2940 	if (errcode != 0) {
2941 	    xmlFree(ret);
2942 	    return(NULL);
2943 	}
2944     }
2945 
2946     return(ret);
2947 }
2948 
2949 /**
2950  * xmlParserInputBufferCreateStatic:
2951  * @mem:  the memory input
2952  * @size:  the length of the memory block
2953  * @enc:  the charset encoding if known
2954  *
2955  * Create a buffered parser input for the progressive parsing for the input
2956  * from an immutable memory area. This will not copy the memory area to
2957  * the buffer, but the memory is expected to be available until the end of
2958  * the parsing, this is useful for example when using mmap'ed file.
2959  *
2960  * Returns the new parser input or NULL
2961  */
2962 xmlParserInputBufferPtr
xmlParserInputBufferCreateStatic(const char * mem,int size,xmlCharEncoding enc)2963 xmlParserInputBufferCreateStatic(const char *mem, int size,
2964                                  xmlCharEncoding enc) {
2965     xmlParserInputBufferPtr ret;
2966 
2967     if (size < 0) return(NULL);
2968     if (mem == NULL) return(NULL);
2969 
2970     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2971     if (ret == NULL) {
2972 	xmlIOErrMemory("creating input buffer");
2973 	return(NULL);
2974     }
2975     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
2976     ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
2977     if (ret->buffer == NULL) {
2978         xmlFree(ret);
2979 	return(NULL);
2980     }
2981     ret->encoder = xmlGetCharEncodingHandler(enc);
2982     if (ret->encoder != NULL)
2983         ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2984     else
2985         ret->raw = NULL;
2986     ret->compressed = -1;
2987     ret->context = (void *) mem;
2988     ret->readcallback = NULL;
2989     ret->closecallback = NULL;
2990 
2991     return(ret);
2992 }
2993 
2994 #ifdef LIBXML_OUTPUT_ENABLED
2995 /**
2996  * xmlOutputBufferCreateFd:
2997  * @fd:  a file descriptor number
2998  * @encoder:  the encoding converter or NULL
2999  *
3000  * Create a buffered output for the progressive saving
3001  * to a file descriptor
3002  *
3003  * Returns the new parser output or NULL
3004  */
3005 xmlOutputBufferPtr
xmlOutputBufferCreateFd(int fd,xmlCharEncodingHandlerPtr encoder)3006 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3007     xmlOutputBufferPtr ret;
3008 
3009     if (fd < 0) return(NULL);
3010 
3011     ret = xmlAllocOutputBufferInternal(encoder);
3012     if (ret != NULL) {
3013         ret->context = (void *) (ptrdiff_t) fd;
3014 	ret->writecallback = xmlFdWrite;
3015 	ret->closecallback = NULL;
3016     }
3017 
3018     return(ret);
3019 }
3020 #endif /* LIBXML_OUTPUT_ENABLED */
3021 
3022 /**
3023  * xmlParserInputBufferCreateIO:
3024  * @ioread:  an I/O read function
3025  * @ioclose:  an I/O close function
3026  * @ioctx:  an I/O handler
3027  * @enc:  the charset encoding if known
3028  *
3029  * Create a buffered parser input for the progressive parsing for the input
3030  * from an I/O handler
3031  *
3032  * Returns the new parser input or NULL
3033  */
3034 xmlParserInputBufferPtr
xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx,xmlCharEncoding enc)3035 xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
3036 	 xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
3037     xmlParserInputBufferPtr ret;
3038 
3039     if (ioread == NULL) return(NULL);
3040 
3041     ret = xmlAllocParserInputBuffer(enc);
3042     if (ret != NULL) {
3043         ret->context = (void *) ioctx;
3044 	ret->readcallback = ioread;
3045 	ret->closecallback = ioclose;
3046     }
3047 
3048     return(ret);
3049 }
3050 
3051 #ifdef LIBXML_OUTPUT_ENABLED
3052 /**
3053  * xmlOutputBufferCreateIO:
3054  * @iowrite:  an I/O write function
3055  * @ioclose:  an I/O close function
3056  * @ioctx:  an I/O handler
3057  * @encoder:  the charset encoding if known
3058  *
3059  * Create a buffered output for the progressive saving
3060  * to an I/O handler
3061  *
3062  * Returns the new parser output or NULL
3063  */
3064 xmlOutputBufferPtr
xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,xmlOutputCloseCallback ioclose,void * ioctx,xmlCharEncodingHandlerPtr encoder)3065 xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite,
3066 	 xmlOutputCloseCallback  ioclose, void *ioctx,
3067 	 xmlCharEncodingHandlerPtr encoder) {
3068     xmlOutputBufferPtr ret;
3069 
3070     if (iowrite == NULL) return(NULL);
3071 
3072     ret = xmlAllocOutputBufferInternal(encoder);
3073     if (ret != NULL) {
3074         ret->context = (void *) ioctx;
3075 	ret->writecallback = iowrite;
3076 	ret->closecallback = ioclose;
3077     }
3078 
3079     return(ret);
3080 }
3081 #endif /* LIBXML_OUTPUT_ENABLED */
3082 
3083 /**
3084  * xmlParserInputBufferCreateFilenameDefault:
3085  * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3086  *
3087  * Registers a callback for URI input file handling
3088  *
3089  * Returns the old value of the registration function
3090  */
3091 xmlParserInputBufferCreateFilenameFunc
xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)3092 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3093 {
3094     xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3095     if (old == NULL) {
3096 		old = __xmlParserInputBufferCreateFilename;
3097 	}
3098 
3099     xmlParserInputBufferCreateFilenameValue = func;
3100     return(old);
3101 }
3102 
3103 /**
3104  * xmlOutputBufferCreateFilenameDefault:
3105  * @func: function pointer to the new OutputBufferCreateFilenameFunc
3106  *
3107  * Registers a callback for URI output file handling
3108  *
3109  * Returns the old value of the registration function
3110  */
3111 xmlOutputBufferCreateFilenameFunc
xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)3112 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3113 {
3114     xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3115 #ifdef LIBXML_OUTPUT_ENABLED
3116     if (old == NULL) {
3117 		old = __xmlOutputBufferCreateFilename;
3118 	}
3119 #endif
3120     xmlOutputBufferCreateFilenameValue = func;
3121     return(old);
3122 }
3123 
3124 /**
3125  * xmlParserInputBufferPush:
3126  * @in:  a buffered parser input
3127  * @len:  the size in bytes of the array.
3128  * @buf:  an char array
3129  *
3130  * Push the content of the arry in the input buffer
3131  * This routine handle the I18N transcoding to internal UTF-8
3132  * This is used when operating the parser in progressive (push) mode.
3133  *
3134  * Returns the number of chars read and stored in the buffer, or -1
3135  *         in case of error.
3136  */
3137 int
xmlParserInputBufferPush(xmlParserInputBufferPtr in,int len,const char * buf)3138 xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3139 	                 int len, const char *buf) {
3140     int nbchars = 0;
3141     int ret;
3142 
3143     if (len < 0) return(0);
3144     if ((in == NULL) || (in->error)) return(-1);
3145     if (in->encoder != NULL) {
3146         unsigned int use;
3147 
3148         /*
3149 	 * Store the data in the incoming raw buffer
3150 	 */
3151         if (in->raw == NULL) {
3152 	    in->raw = xmlBufCreate();
3153 	}
3154 	ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
3155 	if (ret != 0)
3156 	    return(-1);
3157 
3158 	/*
3159 	 * convert as much as possible to the parser reading buffer.
3160 	 */
3161 	use = xmlBufUse(in->raw);
3162 	nbchars = xmlCharEncInput(in, 1);
3163 	if (nbchars < 0) {
3164 	    xmlIOErr(XML_IO_ENCODER, NULL);
3165 	    in->error = XML_IO_ENCODER;
3166 	    return(-1);
3167 	}
3168 	in->rawconsumed += (use - xmlBufUse(in->raw));
3169     } else {
3170 	nbchars = len;
3171         ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
3172 	if (ret != 0)
3173 	    return(-1);
3174     }
3175 #ifdef DEBUG_INPUT
3176     xmlGenericError(xmlGenericErrorContext,
3177 	    "I/O: pushed %d chars, buffer %d/%d\n",
3178             nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
3179 #endif
3180     return(nbchars);
3181 }
3182 
3183 /**
3184  * endOfInput:
3185  *
3186  * When reading from an Input channel indicated end of file or error
3187  * don't reread from it again.
3188  */
3189 static int
endOfInput(void * context ATTRIBUTE_UNUSED,char * buffer ATTRIBUTE_UNUSED,int len ATTRIBUTE_UNUSED)3190 endOfInput (void * context ATTRIBUTE_UNUSED,
3191 	    char * buffer ATTRIBUTE_UNUSED,
3192 	    int len ATTRIBUTE_UNUSED) {
3193     return(0);
3194 }
3195 
3196 /**
3197  * xmlParserInputBufferGrow:
3198  * @in:  a buffered parser input
3199  * @len:  indicative value of the amount of chars to read
3200  *
3201  * Grow up the content of the input buffer, the old data are preserved
3202  * This routine handle the I18N transcoding to internal UTF-8
3203  * This routine is used when operating the parser in normal (pull) mode
3204  *
3205  * TODO: one should be able to remove one extra copy by copying directly
3206  *       onto in->buffer or in->raw
3207  *
3208  * Returns the number of chars read and stored in the buffer, or -1
3209  *         in case of error.
3210  */
3211 int
xmlParserInputBufferGrow(xmlParserInputBufferPtr in,int len)3212 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3213     char *buffer = NULL;
3214     int res = 0;
3215     int nbchars = 0;
3216 
3217     if ((in == NULL) || (in->error)) return(-1);
3218     if ((len <= MINLEN) && (len != 4))
3219         len = MINLEN;
3220 
3221     if (xmlBufAvail(in->buffer) <= 0) {
3222 	xmlIOErr(XML_IO_BUFFER_FULL, NULL);
3223 	in->error = XML_IO_BUFFER_FULL;
3224 	return(-1);
3225     }
3226 
3227     if (xmlBufGrow(in->buffer, len + 1) < 0) {
3228         xmlIOErrMemory("growing input buffer");
3229         in->error = XML_ERR_NO_MEMORY;
3230         return(-1);
3231     }
3232     buffer = (char *)xmlBufEnd(in->buffer);
3233 
3234     /*
3235      * Call the read method for this I/O type.
3236      */
3237     if (in->readcallback != NULL) {
3238 	res = in->readcallback(in->context, &buffer[0], len);
3239 	if (res <= 0)
3240 	    in->readcallback = endOfInput;
3241     } else {
3242 	xmlIOErr(XML_IO_NO_INPUT, NULL);
3243 	in->error = XML_IO_NO_INPUT;
3244 	return(-1);
3245     }
3246     if (res < 0) {
3247 	return(-1);
3248     }
3249 
3250     /*
3251      * try to establish compressed status of input if not done already
3252      */
3253     if (in->compressed == -1) {
3254 #ifdef LIBXML_LZMA_ENABLED
3255 	if (in->readcallback == xmlXzfileRead)
3256             in->compressed = __libxml2_xzcompressed(in->context);
3257 #endif
3258     }
3259 
3260     len = res;
3261     if (in->encoder != NULL) {
3262         unsigned int use;
3263 
3264         /*
3265 	 * Store the data in the incoming raw buffer
3266 	 */
3267         if (in->raw == NULL) {
3268 	    in->raw = xmlBufCreate();
3269 	}
3270 	res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
3271 	if (res != 0)
3272 	    return(-1);
3273 
3274 	/*
3275 	 * convert as much as possible to the parser reading buffer.
3276 	 */
3277 	use = xmlBufUse(in->raw);
3278 	nbchars = xmlCharEncInput(in, 1);
3279 	if (nbchars < 0) {
3280 	    xmlIOErr(XML_IO_ENCODER, NULL);
3281 	    in->error = XML_IO_ENCODER;
3282 	    return(-1);
3283 	}
3284 	in->rawconsumed += (use - xmlBufUse(in->raw));
3285     } else {
3286 	nbchars = len;
3287         xmlBufAddLen(in->buffer, nbchars);
3288     }
3289 #ifdef DEBUG_INPUT
3290     xmlGenericError(xmlGenericErrorContext,
3291 	    "I/O: read %d chars, buffer %d\n",
3292             nbchars, xmlBufUse(in->buffer));
3293 #endif
3294     return(nbchars);
3295 }
3296 
3297 /**
3298  * xmlParserInputBufferRead:
3299  * @in:  a buffered parser input
3300  * @len:  indicative value of the amount of chars to read
3301  *
3302  * Refresh the content of the input buffer, the old data are considered
3303  * consumed
3304  * This routine handle the I18N transcoding to internal UTF-8
3305  *
3306  * Returns the number of chars read and stored in the buffer, or -1
3307  *         in case of error.
3308  */
3309 int
xmlParserInputBufferRead(xmlParserInputBufferPtr in,int len)3310 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
3311     if ((in == NULL) || (in->error)) return(-1);
3312     if (in->readcallback != NULL)
3313 	return(xmlParserInputBufferGrow(in, len));
3314     else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
3315 	return(0);
3316     else
3317         return(-1);
3318 }
3319 
3320 #ifdef LIBXML_OUTPUT_ENABLED
3321 /**
3322  * xmlOutputBufferWrite:
3323  * @out:  a buffered parser output
3324  * @len:  the size in bytes of the array.
3325  * @buf:  an char array
3326  *
3327  * Write the content of the array in the output I/O buffer
3328  * This routine handle the I18N transcoding from internal UTF-8
3329  * The buffer is lossless, i.e. will store in case of partial
3330  * or delayed writes.
3331  *
3332  * Returns the number of chars immediately written, or -1
3333  *         in case of error.
3334  */
3335 int
xmlOutputBufferWrite(xmlOutputBufferPtr out,int len,const char * buf)3336 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3337     int nbchars = 0; /* number of chars to output to I/O */
3338     int ret;         /* return from function call */
3339     int written = 0; /* number of char written to I/O so far */
3340     int chunk;       /* number of byte current processed from buf */
3341 
3342     if ((out == NULL) || (out->error)) return(-1);
3343     if (len < 0) return(0);
3344     if (out->error) return(-1);
3345 
3346     do {
3347 	chunk = len;
3348 	if (chunk > 4 * MINLEN)
3349 	    chunk = 4 * MINLEN;
3350 
3351 	/*
3352 	 * first handle encoding stuff.
3353 	 */
3354 	if (out->encoder != NULL) {
3355 	    /*
3356 	     * Store the data in the incoming raw buffer
3357 	     */
3358 	    if (out->conv == NULL) {
3359 		out->conv = xmlBufCreate();
3360 	    }
3361 	    ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3362 	    if (ret != 0)
3363 	        return(-1);
3364 
3365 	    if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
3366 		goto done;
3367 
3368 	    /*
3369 	     * convert as much as possible to the parser reading buffer.
3370 	     */
3371 	    ret = xmlCharEncOutput(out, 0);
3372 	    if ((ret < 0) && (ret != -3)) {
3373 		xmlIOErr(XML_IO_ENCODER, NULL);
3374 		out->error = XML_IO_ENCODER;
3375 		return(-1);
3376 	    }
3377             if (out->writecallback)
3378 	        nbchars = xmlBufUse(out->conv);
3379             else
3380                 nbchars = ret;
3381 	} else {
3382 	    ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3383 	    if (ret != 0)
3384 	        return(-1);
3385             if (out->writecallback)
3386 	        nbchars = xmlBufUse(out->buffer);
3387             else
3388                 nbchars = chunk;
3389 	}
3390 	buf += chunk;
3391 	len -= chunk;
3392 
3393 	if (out->writecallback) {
3394             if ((nbchars < MINLEN) && (len <= 0))
3395                 goto done;
3396 
3397 	    /*
3398 	     * second write the stuff to the I/O channel
3399 	     */
3400 	    if (out->encoder != NULL) {
3401 		ret = out->writecallback(out->context,
3402                            (const char *)xmlBufContent(out->conv), nbchars);
3403 		if (ret >= 0)
3404 		    xmlBufShrink(out->conv, ret);
3405 	    } else {
3406 		ret = out->writecallback(out->context,
3407                            (const char *)xmlBufContent(out->buffer), nbchars);
3408 		if (ret >= 0)
3409 		    xmlBufShrink(out->buffer, ret);
3410 	    }
3411 	    if (ret < 0) {
3412 		xmlIOErr(XML_IO_WRITE, NULL);
3413 		out->error = XML_IO_WRITE;
3414 		return(ret);
3415 	    }
3416             if (out->written > INT_MAX - ret)
3417                 out->written = INT_MAX;
3418             else
3419                 out->written += ret;
3420 	}
3421 	written += nbchars;
3422     } while (len > 0);
3423 
3424 done:
3425 #ifdef DEBUG_INPUT
3426     xmlGenericError(xmlGenericErrorContext,
3427 	    "I/O: wrote %d chars\n", written);
3428 #endif
3429     return(written);
3430 }
3431 
3432 /**
3433  * xmlEscapeContent:
3434  * @out:  a pointer to an array of bytes to store the result
3435  * @outlen:  the length of @out
3436  * @in:  a pointer to an array of unescaped UTF-8 bytes
3437  * @inlen:  the length of @in
3438  *
3439  * Take a block of UTF-8 chars in and escape them.
3440  * Returns 0 if success, or -1 otherwise
3441  * The value of @inlen after return is the number of octets consumed
3442  *     if the return value is positive, else unpredictable.
3443  * The value of @outlen after return is the number of octets consumed.
3444  */
3445 static int
xmlEscapeContent(unsigned char * out,int * outlen,const xmlChar * in,int * inlen)3446 xmlEscapeContent(unsigned char* out, int *outlen,
3447                  const xmlChar* in, int *inlen) {
3448     unsigned char* outstart = out;
3449     const unsigned char* base = in;
3450     unsigned char* outend = out + *outlen;
3451     const unsigned char* inend;
3452 
3453     inend = in + (*inlen);
3454 
3455     while ((in < inend) && (out < outend)) {
3456 	if (*in == '<') {
3457 	    if (outend - out < 4) break;
3458 	    *out++ = '&';
3459 	    *out++ = 'l';
3460 	    *out++ = 't';
3461 	    *out++ = ';';
3462 	} else if (*in == '>') {
3463 	    if (outend - out < 4) break;
3464 	    *out++ = '&';
3465 	    *out++ = 'g';
3466 	    *out++ = 't';
3467 	    *out++ = ';';
3468 	} else if (*in == '&') {
3469 	    if (outend - out < 5) break;
3470 	    *out++ = '&';
3471 	    *out++ = 'a';
3472 	    *out++ = 'm';
3473 	    *out++ = 'p';
3474 	    *out++ = ';';
3475 	} else if (*in == '\r') {
3476 	    if (outend - out < 5) break;
3477 	    *out++ = '&';
3478 	    *out++ = '#';
3479 	    *out++ = '1';
3480 	    *out++ = '3';
3481 	    *out++ = ';';
3482 	} else {
3483 	    *out++ = (unsigned char) *in;
3484 	}
3485 	++in;
3486     }
3487     *outlen = out - outstart;
3488     *inlen = in - base;
3489     return(0);
3490 }
3491 
3492 /**
3493  * xmlOutputBufferWriteEscape:
3494  * @out:  a buffered parser output
3495  * @str:  a zero terminated UTF-8 string
3496  * @escaping:  an optional escaping function (or NULL)
3497  *
3498  * Write the content of the string in the output I/O buffer
3499  * This routine escapes the characters and then handle the I18N
3500  * transcoding from internal UTF-8
3501  * The buffer is lossless, i.e. will store in case of partial
3502  * or delayed writes.
3503  *
3504  * Returns the number of chars immediately written, or -1
3505  *         in case of error.
3506  */
3507 int
xmlOutputBufferWriteEscape(xmlOutputBufferPtr out,const xmlChar * str,xmlCharEncodingOutputFunc escaping)3508 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3509                            xmlCharEncodingOutputFunc escaping) {
3510     int nbchars = 0; /* number of chars to output to I/O */
3511     int ret;         /* return from function call */
3512     int written = 0; /* number of char written to I/O so far */
3513     int oldwritten=0;/* loop guard */
3514     int chunk;       /* number of byte currently processed from str */
3515     int len;         /* number of bytes in str */
3516     int cons;        /* byte from str consumed */
3517 
3518     if ((out == NULL) || (out->error) || (str == NULL) ||
3519         (out->buffer == NULL) ||
3520 	(xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3521         return(-1);
3522     len = strlen((const char *)str);
3523     if (len < 0) return(0);
3524     if (out->error) return(-1);
3525     if (escaping == NULL) escaping = xmlEscapeContent;
3526 
3527     do {
3528         oldwritten = written;
3529 
3530         /*
3531 	 * how many bytes to consume and how many bytes to store.
3532 	 */
3533 	cons = len;
3534 	chunk = xmlBufAvail(out->buffer) - 1;
3535 
3536         /*
3537 	 * make sure we have enough room to save first, if this is
3538 	 * not the case force a flush, but make sure we stay in the loop
3539 	 */
3540 	if (chunk < 40) {
3541 	    if (xmlBufGrow(out->buffer, 100) < 0)
3542 	        return(-1);
3543             oldwritten = -1;
3544 	    continue;
3545 	}
3546 
3547 	/*
3548 	 * first handle encoding stuff.
3549 	 */
3550 	if (out->encoder != NULL) {
3551 	    /*
3552 	     * Store the data in the incoming raw buffer
3553 	     */
3554 	    if (out->conv == NULL) {
3555 		out->conv = xmlBufCreate();
3556 	    }
3557 	    ret = escaping(xmlBufEnd(out->buffer) ,
3558 	                   &chunk, str, &cons);
3559 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3560 	        return(-1);
3561             xmlBufAddLen(out->buffer, chunk);
3562 
3563 	    if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
3564 		goto done;
3565 
3566 	    /*
3567 	     * convert as much as possible to the output buffer.
3568 	     */
3569 	    ret = xmlCharEncOutput(out, 0);
3570 	    if ((ret < 0) && (ret != -3)) {
3571 		xmlIOErr(XML_IO_ENCODER, NULL);
3572 		out->error = XML_IO_ENCODER;
3573 		return(-1);
3574 	    }
3575             if (out->writecallback)
3576 	        nbchars = xmlBufUse(out->conv);
3577             else
3578                 nbchars = ret;
3579 	} else {
3580 	    ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
3581 	    if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3582 	        return(-1);
3583             xmlBufAddLen(out->buffer, chunk);
3584             if (out->writecallback)
3585 	        nbchars = xmlBufUse(out->buffer);
3586             else
3587                 nbchars = chunk;
3588 	}
3589 	str += cons;
3590 	len -= cons;
3591 
3592 	if (out->writecallback) {
3593             if ((nbchars < MINLEN) && (len <= 0))
3594                 goto done;
3595 
3596 	    /*
3597 	     * second write the stuff to the I/O channel
3598 	     */
3599 	    if (out->encoder != NULL) {
3600 		ret = out->writecallback(out->context,
3601                            (const char *)xmlBufContent(out->conv), nbchars);
3602 		if (ret >= 0)
3603 		    xmlBufShrink(out->conv, ret);
3604 	    } else {
3605 		ret = out->writecallback(out->context,
3606                            (const char *)xmlBufContent(out->buffer), nbchars);
3607 		if (ret >= 0)
3608 		    xmlBufShrink(out->buffer, ret);
3609 	    }
3610 	    if (ret < 0) {
3611 		xmlIOErr(XML_IO_WRITE, NULL);
3612 		out->error = XML_IO_WRITE;
3613 		return(ret);
3614 	    }
3615             if (out->written > INT_MAX - ret)
3616                 out->written = INT_MAX;
3617             else
3618                 out->written += ret;
3619 	} else if (xmlBufAvail(out->buffer) < MINLEN) {
3620 	    xmlBufGrow(out->buffer, MINLEN);
3621 	}
3622 	written += nbchars;
3623     } while ((len > 0) && (oldwritten != written));
3624 
3625 done:
3626 #ifdef DEBUG_INPUT
3627     xmlGenericError(xmlGenericErrorContext,
3628 	    "I/O: wrote %d chars\n", written);
3629 #endif
3630     return(written);
3631 }
3632 
3633 /**
3634  * xmlOutputBufferWriteString:
3635  * @out:  a buffered parser output
3636  * @str:  a zero terminated C string
3637  *
3638  * Write the content of the string in the output I/O buffer
3639  * This routine handle the I18N transcoding from internal UTF-8
3640  * The buffer is lossless, i.e. will store in case of partial
3641  * or delayed writes.
3642  *
3643  * Returns the number of chars immediately written, or -1
3644  *         in case of error.
3645  */
3646 int
xmlOutputBufferWriteString(xmlOutputBufferPtr out,const char * str)3647 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3648     int len;
3649 
3650     if ((out == NULL) || (out->error)) return(-1);
3651     if (str == NULL)
3652         return(-1);
3653     len = strlen(str);
3654 
3655     if (len > 0)
3656 	return(xmlOutputBufferWrite(out, len, str));
3657     return(len);
3658 }
3659 
3660 /**
3661  * xmlOutputBufferFlush:
3662  * @out:  a buffered output
3663  *
3664  * flushes the output I/O channel
3665  *
3666  * Returns the number of byte written or -1 in case of error.
3667  */
3668 int
xmlOutputBufferFlush(xmlOutputBufferPtr out)3669 xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3670     int nbchars = 0, ret = 0;
3671 
3672     if ((out == NULL) || (out->error)) return(-1);
3673     /*
3674      * first handle encoding stuff.
3675      */
3676     if ((out->conv != NULL) && (out->encoder != NULL)) {
3677 	/*
3678 	 * convert as much as possible to the parser output buffer.
3679 	 */
3680 	do {
3681 	    nbchars = xmlCharEncOutput(out, 0);
3682 	    if (nbchars < 0) {
3683 		xmlIOErr(XML_IO_ENCODER, NULL);
3684 		out->error = XML_IO_ENCODER;
3685 		return(-1);
3686 	    }
3687 	} while (nbchars);
3688     }
3689 
3690     /*
3691      * second flush the stuff to the I/O channel
3692      */
3693     if ((out->conv != NULL) && (out->encoder != NULL) &&
3694 	(out->writecallback != NULL)) {
3695 	ret = out->writecallback(out->context,
3696                                  (const char *)xmlBufContent(out->conv),
3697                                  xmlBufUse(out->conv));
3698 	if (ret >= 0)
3699 	    xmlBufShrink(out->conv, ret);
3700     } else if (out->writecallback != NULL) {
3701 	ret = out->writecallback(out->context,
3702                                  (const char *)xmlBufContent(out->buffer),
3703                                  xmlBufUse(out->buffer));
3704 	if (ret >= 0)
3705 	    xmlBufShrink(out->buffer, ret);
3706     }
3707     if (ret < 0) {
3708 	xmlIOErr(XML_IO_FLUSH, NULL);
3709 	out->error = XML_IO_FLUSH;
3710 	return(ret);
3711     }
3712     if (out->written > INT_MAX - ret)
3713         out->written = INT_MAX;
3714     else
3715         out->written += ret;
3716 
3717 #ifdef DEBUG_INPUT
3718     xmlGenericError(xmlGenericErrorContext,
3719 	    "I/O: flushed %d chars\n", ret);
3720 #endif
3721     return(ret);
3722 }
3723 #endif /* LIBXML_OUTPUT_ENABLED */
3724 
3725 /**
3726  * xmlParserGetDirectory:
3727  * @filename:  the path to a file
3728  *
3729  * lookup the directory for that file
3730  *
3731  * Returns a new allocated string containing the directory, or NULL.
3732  */
3733 char *
xmlParserGetDirectory(const char * filename)3734 xmlParserGetDirectory(const char *filename) {
3735     char *ret = NULL;
3736     char dir[1024];
3737     char *cur;
3738 
3739 #ifdef _WIN32_WCE  /* easy way by now ... wince does not have dirs! */
3740     return NULL;
3741 #endif
3742 
3743     if (xmlInputCallbackInitialized == 0)
3744 	xmlRegisterDefaultInputCallbacks();
3745 
3746     if (filename == NULL) return(NULL);
3747 
3748 #if defined(_WIN32) && !defined(__CYGWIN__)
3749 #   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3750 #else
3751 #   define IS_XMLPGD_SEP(ch) (ch=='/')
3752 #endif
3753 
3754     strncpy(dir, filename, 1023);
3755     dir[1023] = 0;
3756     cur = &dir[strlen(dir)];
3757     while (cur > dir) {
3758          if (IS_XMLPGD_SEP(*cur)) break;
3759 	 cur --;
3760     }
3761     if (IS_XMLPGD_SEP(*cur)) {
3762         if (cur == dir) dir[1] = 0;
3763 	else *cur = 0;
3764 	ret = xmlMemStrdup(dir);
3765     } else {
3766         if (getcwd(dir, 1024) != NULL) {
3767 	    dir[1023] = 0;
3768 	    ret = xmlMemStrdup(dir);
3769 	}
3770     }
3771     return(ret);
3772 #undef IS_XMLPGD_SEP
3773 }
3774 
3775 /****************************************************************
3776  *								*
3777  *		External entities loading			*
3778  *								*
3779  ****************************************************************/
3780 
3781 /**
3782  * xmlCheckHTTPInput:
3783  * @ctxt: an XML parser context
3784  * @ret: an XML parser input
3785  *
3786  * Check an input in case it was created from an HTTP stream, in that
3787  * case it will handle encoding and update of the base URL in case of
3788  * redirection. It also checks for HTTP errors in which case the input
3789  * is cleanly freed up and an appropriate error is raised in context
3790  *
3791  * Returns the input or NULL in case of HTTP error.
3792  */
3793 xmlParserInputPtr
xmlCheckHTTPInput(xmlParserCtxtPtr ctxt,xmlParserInputPtr ret)3794 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3795 #ifdef LIBXML_HTTP_ENABLED
3796     if ((ret != NULL) && (ret->buf != NULL) &&
3797         (ret->buf->readcallback == xmlIOHTTPRead) &&
3798         (ret->buf->context != NULL)) {
3799         const char *encoding;
3800         const char *redir;
3801         const char *mime;
3802         int code;
3803 
3804         code = xmlNanoHTTPReturnCode(ret->buf->context);
3805         if (code >= 400) {
3806             /* fatal error */
3807 	    if (ret->filename != NULL)
3808 		__xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
3809                          (const char *) ret->filename);
3810 	    else
3811 		__xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
3812             xmlFreeInputStream(ret);
3813             ret = NULL;
3814         } else {
3815 
3816             mime = xmlNanoHTTPMimeType(ret->buf->context);
3817             if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3818                 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3819                 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3820                 if (encoding != NULL) {
3821                     xmlCharEncodingHandlerPtr handler;
3822 
3823                     handler = xmlFindCharEncodingHandler(encoding);
3824                     if (handler != NULL) {
3825                         xmlSwitchInputEncoding(ctxt, ret, handler);
3826                     } else {
3827                         __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3828                                          "Unknown encoding %s",
3829                                          BAD_CAST encoding, NULL);
3830                     }
3831                     if (ret->encoding == NULL)
3832                         ret->encoding = xmlStrdup(BAD_CAST encoding);
3833                 }
3834 #if 0
3835             } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3836 #endif
3837             }
3838             redir = xmlNanoHTTPRedir(ret->buf->context);
3839             if (redir != NULL) {
3840                 if (ret->filename != NULL)
3841                     xmlFree((xmlChar *) ret->filename);
3842                 if (ret->directory != NULL) {
3843                     xmlFree((xmlChar *) ret->directory);
3844                     ret->directory = NULL;
3845                 }
3846                 ret->filename =
3847                     (char *) xmlStrdup((const xmlChar *) redir);
3848             }
3849         }
3850     }
3851 #endif
3852     return(ret);
3853 }
3854 
xmlNoNetExists(const char * URL)3855 static int xmlNoNetExists(const char *URL) {
3856     const char *path;
3857 
3858     if (URL == NULL)
3859 	return(0);
3860 
3861     if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
3862 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3863 	path = &URL[17];
3864 #else
3865 	path = &URL[16];
3866 #endif
3867     else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
3868 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3869 	path = &URL[8];
3870 #else
3871 	path = &URL[7];
3872 #endif
3873     } else
3874 	path = URL;
3875 
3876     return xmlCheckFilename(path);
3877 }
3878 
3879 #ifdef LIBXML_CATALOG_ENABLED
3880 
3881 /**
3882  * xmlResolveResourceFromCatalog:
3883  * @URL:  the URL for the entity to load
3884  * @ID:  the System ID for the entity to load
3885  * @ctxt:  the context in which the entity is called or NULL
3886  *
3887  * Resolves the URL and ID against the appropriate catalog.
3888  * This function is used by xmlDefaultExternalEntityLoader and
3889  * xmlNoNetExternalEntityLoader.
3890  *
3891  * Returns a new allocated URL, or NULL.
3892  */
3893 static xmlChar *
xmlResolveResourceFromCatalog(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)3894 xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3895                               xmlParserCtxtPtr ctxt) {
3896     xmlChar *resource = NULL;
3897     xmlCatalogAllow pref;
3898 
3899     /*
3900      * If the resource doesn't exists as a file,
3901      * try to load it from the resource pointed in the catalogs
3902      */
3903     pref = xmlCatalogGetDefaults();
3904 
3905     if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3906 	/*
3907 	 * Do a local lookup
3908 	 */
3909 	if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3910 	    ((pref == XML_CATA_ALLOW_ALL) ||
3911 	     (pref == XML_CATA_ALLOW_DOCUMENT))) {
3912 	    resource = xmlCatalogLocalResolve(ctxt->catalogs,
3913 					      (const xmlChar *)ID,
3914 					      (const xmlChar *)URL);
3915         }
3916 	/*
3917 	 * Try a global lookup
3918 	 */
3919 	if ((resource == NULL) &&
3920 	    ((pref == XML_CATA_ALLOW_ALL) ||
3921 	     (pref == XML_CATA_ALLOW_GLOBAL))) {
3922 	    resource = xmlCatalogResolve((const xmlChar *)ID,
3923 					 (const xmlChar *)URL);
3924 	}
3925 	if ((resource == NULL) && (URL != NULL))
3926 	    resource = xmlStrdup((const xmlChar *) URL);
3927 
3928 	/*
3929 	 * TODO: do an URI lookup on the reference
3930 	 */
3931 	if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3932 	    xmlChar *tmp = NULL;
3933 
3934 	    if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3935 		((pref == XML_CATA_ALLOW_ALL) ||
3936 		 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3937 		tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3938 	    }
3939 	    if ((tmp == NULL) &&
3940 		((pref == XML_CATA_ALLOW_ALL) ||
3941 	         (pref == XML_CATA_ALLOW_GLOBAL))) {
3942 		tmp = xmlCatalogResolveURI(resource);
3943 	    }
3944 
3945 	    if (tmp != NULL) {
3946 		xmlFree(resource);
3947 		resource = tmp;
3948 	    }
3949 	}
3950     }
3951 
3952     return resource;
3953 }
3954 
3955 #endif
3956 
3957 /**
3958  * xmlDefaultExternalEntityLoader:
3959  * @URL:  the URL for the entity to load
3960  * @ID:  the System ID for the entity to load
3961  * @ctxt:  the context in which the entity is called or NULL
3962  *
3963  * By default we don't load external entities, yet.
3964  *
3965  * Returns a new allocated xmlParserInputPtr, or NULL.
3966  */
3967 static xmlParserInputPtr
xmlDefaultExternalEntityLoader(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)3968 xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
3969                                xmlParserCtxtPtr ctxt)
3970 {
3971     xmlParserInputPtr ret = NULL;
3972     xmlChar *resource = NULL;
3973 
3974 #ifdef DEBUG_EXTERNAL_ENTITIES
3975     xmlGenericError(xmlGenericErrorContext,
3976                     "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
3977 #endif
3978     if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3979         int options = ctxt->options;
3980 
3981 	ctxt->options -= XML_PARSE_NONET;
3982         ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3983 	ctxt->options = options;
3984 	return(ret);
3985     }
3986 #ifdef LIBXML_CATALOG_ENABLED
3987     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
3988 #endif
3989 
3990     if (resource == NULL)
3991         resource = (xmlChar *) URL;
3992 
3993     if (resource == NULL) {
3994         if (ID == NULL)
3995             ID = "NULL";
3996         __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
3997         return (NULL);
3998     }
3999     ret = xmlNewInputFromFile(ctxt, (const char *) resource);
4000     if ((resource != NULL) && (resource != (xmlChar *) URL))
4001         xmlFree(resource);
4002     return (ret);
4003 }
4004 
4005 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4006        xmlDefaultExternalEntityLoader;
4007 
4008 /**
4009  * xmlSetExternalEntityLoader:
4010  * @f:  the new entity resolver function
4011  *
4012  * Changes the defaultexternal entity resolver function for the application
4013  */
4014 void
xmlSetExternalEntityLoader(xmlExternalEntityLoader f)4015 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4016     xmlCurrentExternalEntityLoader = f;
4017 }
4018 
4019 /**
4020  * xmlGetExternalEntityLoader:
4021  *
4022  * Get the default external entity resolver function for the application
4023  *
4024  * Returns the xmlExternalEntityLoader function pointer
4025  */
4026 xmlExternalEntityLoader
xmlGetExternalEntityLoader(void)4027 xmlGetExternalEntityLoader(void) {
4028     return(xmlCurrentExternalEntityLoader);
4029 }
4030 
4031 /**
4032  * xmlLoadExternalEntity:
4033  * @URL:  the URL for the entity to load
4034  * @ID:  the Public ID for the entity to load
4035  * @ctxt:  the context in which the entity is called or NULL
4036  *
4037  * Load an external entity, note that the use of this function for
4038  * unparsed entities may generate problems
4039  *
4040  * Returns the xmlParserInputPtr or NULL
4041  */
4042 xmlParserInputPtr
xmlLoadExternalEntity(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)4043 xmlLoadExternalEntity(const char *URL, const char *ID,
4044                       xmlParserCtxtPtr ctxt) {
4045     if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
4046 	char *canonicFilename;
4047 	xmlParserInputPtr ret;
4048 
4049 	canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4050 	if (canonicFilename == NULL) {
4051             xmlIOErrMemory("building canonical path\n");
4052 	    return(NULL);
4053 	}
4054 
4055 	ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4056 	xmlFree(canonicFilename);
4057 	return(ret);
4058     }
4059     return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4060 }
4061 
4062 /************************************************************************
4063  *									*
4064  *		Disabling Network access				*
4065  *									*
4066  ************************************************************************/
4067 
4068 /**
4069  * xmlNoNetExternalEntityLoader:
4070  * @URL:  the URL for the entity to load
4071  * @ID:  the System ID for the entity to load
4072  * @ctxt:  the context in which the entity is called or NULL
4073  *
4074  * A specific entity loader disabling network accesses, though still
4075  * allowing local catalog accesses for resolution.
4076  *
4077  * Returns a new allocated xmlParserInputPtr, or NULL.
4078  */
4079 xmlParserInputPtr
xmlNoNetExternalEntityLoader(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)4080 xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4081                              xmlParserCtxtPtr ctxt) {
4082     xmlParserInputPtr input = NULL;
4083     xmlChar *resource = NULL;
4084 
4085 #ifdef LIBXML_CATALOG_ENABLED
4086     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4087 #endif
4088 
4089     if (resource == NULL)
4090 	resource = (xmlChar *) URL;
4091 
4092     if (resource != NULL) {
4093         if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4094             (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
4095             xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
4096 	    if (resource != (xmlChar *) URL)
4097 		xmlFree(resource);
4098 	    return(NULL);
4099 	}
4100     }
4101     input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4102     if (resource != (xmlChar *) URL)
4103 	xmlFree(resource);
4104     return(input);
4105 }
4106 
4107 #define bottom_xmlIO
4108 #include "elfgcchack.h"
4109