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