VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/xmlIO.c

Last change on this file was 104106, checked in by vboxsync, 8 weeks ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use