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