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