VirtualBox

source: vbox/trunk/src/libs/libxml2-2.6.30/xmlIO.c@ 34034

Last change on this file since 34034 was 6076, checked in by vboxsync, 17 years ago

Merged dmik/s2 branch (r25959:26751) to the trunk.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette