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