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
9 #define IN_LIBXML
10 #include "libxml.h"
11
12 #include <string.h>
13 #include <stdlib.h>
14 #include <errno.h>
15
16 #ifdef HAVE_SYS_STAT_H
17 #include <sys/stat.h>
18 #endif
19 #ifdef HAVE_FCNTL_H
20 #include <fcntl.h>
21 #endif
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif
25 #ifdef LIBXML_ZLIB_ENABLED
26 #include <zlib.h>
27 #endif
28 #ifdef LIBXML_LZMA_ENABLED
29 #include <lzma.h>
30 #endif
31
32 #if defined(_WIN32)
33 #define WIN32_LEAN_AND_MEAN
34 #include <windows.h>
35 #include <io.h>
36 #include <direct.h>
37 #endif
38
39 #include <libxml/xmlIO.h>
40 #include <libxml/xmlmemory.h>
41 #include <libxml/uri.h>
42 #include <libxml/nanohttp.h>
43 #include <libxml/parserInternals.h>
44 #include <libxml/xmlerror.h>
45 #ifdef LIBXML_CATALOG_ENABLED
46 #include <libxml/catalog.h>
47 #endif
48
49 #include "private/buf.h"
50 #include "private/enc.h"
51 #include "private/error.h"
52 #include "private/io.h"
53
54 /* #define VERBOSE_FAILURE */
55
56 #define MINLEN 4000
57
58 #ifndef STDOUT_FILENO
59 #define STDOUT_FILENO 1
60 #endif
61
62 #ifndef S_ISDIR
63 # ifdef _S_ISDIR
64 # define S_ISDIR(x) _S_ISDIR(x)
65 # elif defined(S_IFDIR)
66 # ifdef S_IFMT
67 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
68 # elif defined(_S_IFMT)
69 # define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
70 # endif
71 # endif
72 #endif
73
74 /*
75 * Input I/O callback sets
76 */
77 typedef struct _xmlInputCallback {
78 xmlInputMatchCallback matchcallback;
79 xmlInputOpenCallback opencallback;
80 xmlInputReadCallback readcallback;
81 xmlInputCloseCallback closecallback;
82 } xmlInputCallback;
83
84 /* This dummy function only marks default IO in the callback table */
85 static int
86 xmlIODefaultMatch(const char *filename);
87
88 #define MAX_INPUT_CALLBACK 10
89
90 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
91 static int xmlInputCallbackNr;
92
93 #ifdef LIBXML_OUTPUT_ENABLED
94 /*
95 * Output I/O callback sets
96 */
97 typedef struct _xmlOutputCallback {
98 xmlOutputMatchCallback matchcallback;
99 xmlOutputOpenCallback opencallback;
100 xmlOutputWriteCallback writecallback;
101 xmlOutputCloseCallback closecallback;
102 } xmlOutputCallback;
103
104 #define MAX_OUTPUT_CALLBACK 10
105
106 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
107 static int xmlOutputCallbackNr;
108 #endif /* LIBXML_OUTPUT_ENABLED */
109
110 /************************************************************************
111 * *
112 * Error handling *
113 * *
114 ************************************************************************/
115
116 /**
117 * xmlIOErr:
118 * @code: the error number
119 *
120 * Convert errno to xmlParserErrors.
121 *
122 * Returns an xmlParserErrors code.
123 */
124 static int
xmlIOErr(int err)125 xmlIOErr(int err)
126 {
127 int code;
128
129 if (err == 0) code = XML_IO_UNKNOWN;
130 #ifdef EACCES
131 else if (err == EACCES) code = XML_IO_EACCES;
132 #endif
133 #ifdef EAGAIN
134 else if (err == EAGAIN) code = XML_IO_EAGAIN;
135 #endif
136 #ifdef EBADF
137 else if (err == EBADF) code = XML_IO_EBADF;
138 #endif
139 #ifdef EBADMSG
140 else if (err == EBADMSG) code = XML_IO_EBADMSG;
141 #endif
142 #ifdef EBUSY
143 else if (err == EBUSY) code = XML_IO_EBUSY;
144 #endif
145 #ifdef ECANCELED
146 else if (err == ECANCELED) code = XML_IO_ECANCELED;
147 #endif
148 #ifdef ECHILD
149 else if (err == ECHILD) code = XML_IO_ECHILD;
150 #endif
151 #ifdef EDEADLK
152 else if (err == EDEADLK) code = XML_IO_EDEADLK;
153 #endif
154 #ifdef EDOM
155 else if (err == EDOM) code = XML_IO_EDOM;
156 #endif
157 #ifdef EEXIST
158 else if (err == EEXIST) code = XML_IO_EEXIST;
159 #endif
160 #ifdef EFAULT
161 else if (err == EFAULT) code = XML_IO_EFAULT;
162 #endif
163 #ifdef EFBIG
164 else if (err == EFBIG) code = XML_IO_EFBIG;
165 #endif
166 #ifdef EINPROGRESS
167 else if (err == EINPROGRESS) code = XML_IO_EINPROGRESS;
168 #endif
169 #ifdef EINTR
170 else if (err == EINTR) code = XML_IO_EINTR;
171 #endif
172 #ifdef EINVAL
173 else if (err == EINVAL) code = XML_IO_EINVAL;
174 #endif
175 #ifdef EIO
176 else if (err == EIO) code = XML_IO_EIO;
177 #endif
178 #ifdef EISDIR
179 else if (err == EISDIR) code = XML_IO_EISDIR;
180 #endif
181 #ifdef EMFILE
182 else if (err == EMFILE) code = XML_IO_EMFILE;
183 #endif
184 #ifdef EMLINK
185 else if (err == EMLINK) code = XML_IO_EMLINK;
186 #endif
187 #ifdef EMSGSIZE
188 else if (err == EMSGSIZE) code = XML_IO_EMSGSIZE;
189 #endif
190 #ifdef ENAMETOOLONG
191 else if (err == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
192 #endif
193 #ifdef ENFILE
194 else if (err == ENFILE) code = XML_IO_ENFILE;
195 #endif
196 #ifdef ENODEV
197 else if (err == ENODEV) code = XML_IO_ENODEV;
198 #endif
199 #ifdef ENOENT
200 else if (err == ENOENT) code = XML_IO_ENOENT;
201 #endif
202 #ifdef ENOEXEC
203 else if (err == ENOEXEC) code = XML_IO_ENOEXEC;
204 #endif
205 #ifdef ENOLCK
206 else if (err == ENOLCK) code = XML_IO_ENOLCK;
207 #endif
208 #ifdef ENOMEM
209 else if (err == ENOMEM) code = XML_IO_ENOMEM;
210 #endif
211 #ifdef ENOSPC
212 else if (err == ENOSPC) code = XML_IO_ENOSPC;
213 #endif
214 #ifdef ENOSYS
215 else if (err == ENOSYS) code = XML_IO_ENOSYS;
216 #endif
217 #ifdef ENOTDIR
218 else if (err == ENOTDIR) code = XML_IO_ENOTDIR;
219 #endif
220 #ifdef ENOTEMPTY
221 else if (err == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
222 #endif
223 #ifdef ENOTSUP
224 else if (err == ENOTSUP) code = XML_IO_ENOTSUP;
225 #endif
226 #ifdef ENOTTY
227 else if (err == ENOTTY) code = XML_IO_ENOTTY;
228 #endif
229 #ifdef ENXIO
230 else if (err == ENXIO) code = XML_IO_ENXIO;
231 #endif
232 #ifdef EPERM
233 else if (err == EPERM) code = XML_IO_EPERM;
234 #endif
235 #ifdef EPIPE
236 else if (err == EPIPE) code = XML_IO_EPIPE;
237 #endif
238 #ifdef ERANGE
239 else if (err == ERANGE) code = XML_IO_ERANGE;
240 #endif
241 #ifdef EROFS
242 else if (err == EROFS) code = XML_IO_EROFS;
243 #endif
244 #ifdef ESPIPE
245 else if (err == ESPIPE) code = XML_IO_ESPIPE;
246 #endif
247 #ifdef ESRCH
248 else if (err == ESRCH) code = XML_IO_ESRCH;
249 #endif
250 #ifdef ETIMEDOUT
251 else if (err == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
252 #endif
253 #ifdef EXDEV
254 else if (err == EXDEV) code = XML_IO_EXDEV;
255 #endif
256 #ifdef ENOTSOCK
257 else if (err == ENOTSOCK) code = XML_IO_ENOTSOCK;
258 #endif
259 #ifdef EISCONN
260 else if (err == EISCONN) code = XML_IO_EISCONN;
261 #endif
262 #ifdef ECONNREFUSED
263 else if (err == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
264 #endif
265 #ifdef ETIMEDOUT
266 else if (err == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
267 #endif
268 #ifdef ENETUNREACH
269 else if (err == ENETUNREACH) code = XML_IO_ENETUNREACH;
270 #endif
271 #ifdef EADDRINUSE
272 else if (err == EADDRINUSE) code = XML_IO_EADDRINUSE;
273 #endif
274 #ifdef EINPROGRESS
275 else if (err == EINPROGRESS) code = XML_IO_EINPROGRESS;
276 #endif
277 #ifdef EALREADY
278 else if (err == EALREADY) code = XML_IO_EALREADY;
279 #endif
280 #ifdef EAFNOSUPPORT
281 else if (err == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
282 #endif
283 else code = XML_IO_UNKNOWN;
284
285 return(code);
286 }
287
288 /************************************************************************
289 * *
290 * Standard I/O for file accesses *
291 * *
292 ************************************************************************/
293
294 #if defined(_WIN32)
295
296 /**
297 * __xmlIOWin32UTF8ToWChar:
298 * @u8String: uft-8 string
299 *
300 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
301 */
302 static wchar_t *
__xmlIOWin32UTF8ToWChar(const char * u8String)303 __xmlIOWin32UTF8ToWChar(const char *u8String)
304 {
305 wchar_t *wString = NULL;
306 int i;
307
308 if (u8String) {
309 int wLen =
310 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
311 -1, NULL, 0);
312 if (wLen) {
313 wString = xmlMalloc(wLen * sizeof(wchar_t));
314 if (wString) {
315 if (MultiByteToWideChar
316 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
317 xmlFree(wString);
318 wString = NULL;
319 }
320 }
321
322 /*
323 * Convert to backward slash
324 */
325 for (i = 0; wString[i] != 0; i++) {
326 if (wString[i] == '/')
327 wString[i] = '\\';
328 }
329 }
330 }
331
332 return wString;
333 }
334
335 #endif
336
337 /**
338 * xmlNormalizeWindowsPath:
339 * @path: the input file path
340 *
341 * DEPRECATED: This never really worked.
342 *
343 * Returns a copy of path.
344 */
345 xmlChar *
xmlNormalizeWindowsPath(const xmlChar * path)346 xmlNormalizeWindowsPath(const xmlChar *path)
347 {
348 return xmlStrdup(path);
349 }
350
351 /**
352 * xmlCheckFilename:
353 * @path: the path to check
354 *
355 * DEPRECATED: Internal function, don't use.
356 *
357 * if stat is not available on the target machine,
358 * returns 1. if stat fails, returns 0 (if calling
359 * stat on the filename fails, it can't be right).
360 * if stat succeeds and the file is a directory,
361 * returns 2. otherwise returns 1.
362 */
363 int
xmlCheckFilename(const char * path)364 xmlCheckFilename(const char *path)
365 {
366 #ifdef HAVE_STAT
367 #if defined(_WIN32)
368 struct _stat stat_buffer;
369 #else
370 struct stat stat_buffer;
371 #endif
372 int res;
373 #endif
374
375 if (path == NULL)
376 return(0);
377
378 #ifdef HAVE_STAT
379 #if defined(_WIN32)
380 {
381 wchar_t *wpath;
382
383 /*
384 * On Windows stat and wstat do not work with long pathname,
385 * which start with '\\?\'
386 */
387 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
388 (path[3] == '\\') )
389 return 1;
390
391 wpath = __xmlIOWin32UTF8ToWChar(path);
392 if (wpath == NULL)
393 return(0);
394 res = _wstat(wpath, &stat_buffer);
395 xmlFree(wpath);
396 }
397 #else
398 res = stat(path, &stat_buffer);
399 #endif
400
401 if (res < 0)
402 return 0;
403
404 #ifdef S_ISDIR
405 if (S_ISDIR(stat_buffer.st_mode))
406 return 2;
407 #endif
408 #endif /* HAVE_STAT */
409
410 return 1;
411 }
412
413 static int
xmlConvertUriToPath(const char * uri,char ** out)414 xmlConvertUriToPath(const char *uri, char **out) {
415 const char *escaped;
416 char *unescaped;
417
418 *out = NULL;
419
420 if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file://localhost/", 17)) {
421 escaped = &uri[16];
422 } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:///", 8)) {
423 escaped = &uri[7];
424 } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:/", 6)) {
425 /* lots of generators seems to lazy to read RFC 1738 */
426 escaped = &uri[5];
427 } else {
428 return(1);
429 }
430
431 #ifdef _WIN32
432 /* Ignore slash like in file:///C:/file.txt */
433 escaped += 1;
434 #endif
435
436 unescaped = xmlURIUnescapeString(escaped, 0, NULL);
437 if (unescaped == NULL)
438 return(-1);
439
440 *out = unescaped;
441 return(0);
442 }
443
444 /**
445 * xmlFdOpen:
446 * @filename: the URI for matching
447 * @out: pointer to resulting context
448 *
449 * Returns an xmlParserErrors code
450 */
451 static int
xmlFdOpen(const char * filename,int write,int * out)452 xmlFdOpen(const char *filename, int write, int *out) {
453 char *fromUri = NULL;
454 int flags;
455 int fd;
456 int ret;
457
458 *out = -1;
459 if (filename == NULL)
460 return(XML_ERR_ARGUMENT);
461
462 if (xmlConvertUriToPath(filename, &fromUri) < 0)
463 return(XML_ERR_NO_MEMORY);
464
465 if (fromUri != NULL)
466 filename = fromUri;
467
468 #if defined(_WIN32)
469 {
470 wchar_t *wpath;
471
472 wpath = __xmlIOWin32UTF8ToWChar(filename);
473 if (wpath == NULL) {
474 xmlFree(fromUri);
475 return(XML_ERR_NO_MEMORY);
476 }
477 if (write)
478 flags = _O_WRONLY | _O_CREAT | _O_TRUNC;
479 else
480 flags = _O_RDONLY;
481 fd = _wopen(wpath, flags | _O_BINARY, 0777);
482 xmlFree(wpath);
483 }
484 #else
485 if (write)
486 flags = O_WRONLY | O_CREAT | O_TRUNC;
487 else
488 flags = O_RDONLY;
489 fd = open(filename, flags, 0777);
490 #endif /* WIN32 */
491
492 if (fd < 0) {
493 /*
494 * Windows and possibly other platforms return EINVAL
495 * for invalid filenames.
496 */
497 if ((errno == ENOENT) || (errno == EINVAL)) {
498 ret = XML_IO_ENOENT;
499 } else {
500 ret = xmlIOErr(errno);
501 }
502 } else {
503 *out = fd;
504 ret = XML_ERR_OK;
505 }
506
507 xmlFree(fromUri);
508 return(ret);
509 }
510
511 /**
512 * xmlFdRead:
513 * @context: the I/O context
514 * @buffer: where to drop data
515 * @len: number of bytes to read
516 *
517 * Read @len bytes to @buffer from the I/O channel.
518 *
519 * Returns the number of bytes read
520 */
521 static int
xmlFdRead(void * context,char * buffer,int len)522 xmlFdRead(void *context, char *buffer, int len) {
523 int fd = (int) (ptrdiff_t) context;
524 int ret = 0;
525 int bytes;
526
527 while (len > 0) {
528 bytes = read(fd, buffer, len);
529 if (bytes < 0) {
530 /*
531 * If we already got some bytes, return them without
532 * raising an error.
533 */
534 if (ret > 0)
535 break;
536 return(-xmlIOErr(errno));
537 }
538 if (bytes == 0)
539 break;
540 ret += bytes;
541 buffer += bytes;
542 len -= bytes;
543 }
544
545 return(ret);
546 }
547
548 #ifdef LIBXML_OUTPUT_ENABLED
549 /**
550 * xmlFdWrite:
551 * @context: the I/O context
552 * @buffer: where to get data
553 * @len: number of bytes to write
554 *
555 * Write @len bytes from @buffer to the I/O channel.
556 *
557 * Returns the number of bytes written
558 */
559 static int
xmlFdWrite(void * context,const char * buffer,int len)560 xmlFdWrite(void *context, const char *buffer, int len) {
561 int fd = (int) (ptrdiff_t) context;
562 int ret = 0;
563 int bytes;
564
565 while (len > 0) {
566 bytes = write(fd, buffer, len);
567 if (bytes < 0)
568 return(-xmlIOErr(errno));
569 ret += bytes;
570 buffer += bytes;
571 len -= bytes;
572 }
573
574 return(ret);
575 }
576 #endif /* LIBXML_OUTPUT_ENABLED */
577
578 /**
579 * xmlFdClose:
580 * @context: the I/O context
581 *
582 * Close an I/O channel
583 *
584 * Returns 0 in case of success and error code otherwise
585 */
586 static int
xmlFdClose(void * context)587 xmlFdClose (void * context) {
588 int ret;
589
590 ret = close((int) (ptrdiff_t) context);
591 if (ret < 0)
592 return(xmlIOErr(errno));
593
594 return(XML_ERR_OK);
595 }
596
597 /**
598 * xmlFileMatch:
599 * @filename: the URI for matching
600 *
601 * DEPRECATED: Internal function, don't use.
602 *
603 * Returns 1 if matches, 0 otherwise
604 */
605 int
xmlFileMatch(const char * filename ATTRIBUTE_UNUSED)606 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
607 return(1);
608 }
609
610 /**
611 * xmlFileOpenSafe:
612 * @filename: the URI for matching
613 * @out: pointer to resulting context
614 *
615 * input from FILE *
616 *
617 * Returns an I/O context or NULL in case of error
618 */
619 static int
xmlFileOpenSafe(const char * filename,int write,void ** out)620 xmlFileOpenSafe(const char *filename, int write, void **out) {
621 char *fromUri = NULL;
622 FILE *fd;
623 int ret = XML_ERR_OK;
624
625 *out = NULL;
626 if (filename == NULL)
627 return(XML_ERR_ARGUMENT);
628
629 if (xmlConvertUriToPath(filename, &fromUri) < 0)
630 return(XML_ERR_NO_MEMORY);
631
632 if (fromUri != NULL)
633 filename = fromUri;
634
635 #if defined(_WIN32)
636 {
637 wchar_t *wpath;
638
639 wpath = __xmlIOWin32UTF8ToWChar(filename);
640 if (wpath == NULL) {
641 xmlFree(fromUri);
642 return(XML_ERR_NO_MEMORY);
643 }
644 fd = _wfopen(wpath, write ? L"wb" : L"rb");
645 xmlFree(wpath);
646 }
647 #else
648 fd = fopen(filename, write ? "wb" : "rb");
649 #endif /* WIN32 */
650
651 if (fd == NULL) {
652 /*
653 * Windows and possibly other platforms return EINVAL
654 * for invalid filenames.
655 */
656 if ((errno == ENOENT) || (errno == EINVAL)) {
657 ret = XML_IO_ENOENT;
658 } else {
659 /*
660 * This error won't be forwarded to the parser context
661 * which will report it a second time.
662 */
663 ret = xmlIOErr(errno);
664 }
665 }
666
667 *out = fd;
668 xmlFree(fromUri);
669 return(ret);
670 }
671
672 /**
673 * xmlFileOpen:
674 * @filename: the URI for matching
675 *
676 * DEPRECATED: Internal function, don't use.
677 *
678 * Returns an IO context or NULL in case or failure
679 */
680 void *
xmlFileOpen(const char * filename)681 xmlFileOpen(const char *filename) {
682 void *context;
683
684 xmlFileOpenSafe(filename, 0, &context);
685 return(context);
686 }
687
688 /**
689 * xmlFileRead:
690 * @context: the I/O context
691 * @buffer: where to drop data
692 * @len: number of bytes to write
693 *
694 * DEPRECATED: Internal function, don't use.
695 *
696 * Returns the number of bytes read or < 0 in case of failure
697 */
698 int
xmlFileRead(void * context,char * buffer,int len)699 xmlFileRead(void * context, char * buffer, int len) {
700 FILE *file = context;
701 size_t bytes;
702
703 if ((context == NULL) || (buffer == NULL))
704 return(-1);
705
706 /*
707 * The C standard doesn't mandate that fread sets errno, only
708 * POSIX does. The Windows documentation isn't really clear.
709 * Set errno to zero which will be reported as unknown error
710 * if fread fails without setting errno.
711 */
712 errno = 0;
713 bytes = fread(buffer, 1, len, file);
714 if ((bytes < (size_t) len) && (ferror(file)))
715 return(-xmlIOErr(errno));
716
717 return(len);
718 }
719
720 #ifdef LIBXML_OUTPUT_ENABLED
721 /**
722 * xmlFileWrite:
723 * @context: the I/O context
724 * @buffer: where to drop data
725 * @len: number of bytes to write
726 *
727 * Write @len bytes from @buffer to the I/O channel.
728 *
729 * Returns the number of bytes written
730 */
731 static int
xmlFileWrite(void * context,const char * buffer,int len)732 xmlFileWrite(void *context, const char *buffer, int len) {
733 FILE *file = context;
734 size_t bytes;
735
736 if ((context == NULL) || (buffer == NULL))
737 return(-1);
738
739 errno = 0;
740 bytes = fwrite(buffer, 1, len, file);
741 if (bytes < (size_t) len)
742 return(-xmlIOErr(errno));
743
744 return(len);
745 }
746 #endif /* LIBXML_OUTPUT_ENABLED */
747
748 /**
749 * xmlFileFlush:
750 * @context: the I/O context
751 *
752 * Flush an I/O channel
753 */
754 static int
xmlFileFlush(void * context)755 xmlFileFlush (void * context) {
756 FILE *file = context;
757
758 if (file == NULL)
759 return(-1);
760
761 if (fflush(file) != 0)
762 return(xmlIOErr(errno));
763
764 return(XML_ERR_OK);
765 }
766
767 /**
768 * xmlFileClose:
769 * @context: the I/O context
770 *
771 * DEPRECATED: Internal function, don't use.
772 *
773 * Returns 0 or -1 an error code case of error
774 */
775 int
xmlFileClose(void * context)776 xmlFileClose (void * context) {
777 FILE *file = context;
778
779 if (context == NULL)
780 return(-1);
781
782 if (file == stdin)
783 return(0);
784 if ((file == stdout) || (file == stderr))
785 return(xmlFileFlush(file));
786
787 if (fclose(file) != 0)
788 return(xmlIOErr(errno));
789
790 return(0);
791 }
792
793 #ifdef LIBXML_OUTPUT_ENABLED
794 /**
795 * xmlBufferWrite:
796 * @context: the xmlBuffer
797 * @buffer: the data to write
798 * @len: number of bytes to write
799 *
800 * Write @len bytes from @buffer to the xml buffer
801 *
802 * Returns the number of bytes written or a negative xmlParserErrors
803 * value.
804 */
805 static int
xmlBufferWrite(void * context,const char * buffer,int len)806 xmlBufferWrite (void * context, const char * buffer, int len) {
807 int ret;
808
809 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
810 if (ret != 0)
811 return(-XML_ERR_NO_MEMORY);
812 return(len);
813 }
814 #endif
815
816 #ifdef LIBXML_ZLIB_ENABLED
817 /************************************************************************
818 * *
819 * I/O for compressed file accesses *
820 * *
821 ************************************************************************/
822
823 /**
824 * xmlGzfileRead:
825 * @context: the I/O context
826 * @buffer: where to drop data
827 * @len: number of bytes to write
828 *
829 * Read @len bytes to @buffer from the compressed I/O channel.
830 *
831 * Returns the number of bytes read.
832 */
833 static int
xmlGzfileRead(void * context,char * buffer,int len)834 xmlGzfileRead (void * context, char * buffer, int len) {
835 int ret;
836
837 ret = gzread((gzFile) context, &buffer[0], len);
838 if (ret < 0)
839 return(-XML_IO_UNKNOWN);
840 return(ret);
841 }
842
843 #ifdef LIBXML_OUTPUT_ENABLED
844 /**
845 * xmlGzfileWrite:
846 * @context: the I/O context
847 * @buffer: where to drop data
848 * @len: number of bytes to write
849 *
850 * Write @len bytes from @buffer to the compressed I/O channel.
851 *
852 * Returns the number of bytes written
853 */
854 static int
xmlGzfileWrite(void * context,const char * buffer,int len)855 xmlGzfileWrite (void * context, const char * buffer, int len) {
856 int ret;
857
858 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
859 if (ret < 0)
860 return(-XML_IO_UNKNOWN);
861 return(ret);
862 }
863 #endif /* LIBXML_OUTPUT_ENABLED */
864
865 /**
866 * xmlGzfileClose:
867 * @context: the I/O context
868 *
869 * Close a compressed I/O channel
870 */
871 static int
xmlGzfileClose(void * context)872 xmlGzfileClose (void * context) {
873 if (gzclose((gzFile) context) != Z_OK)
874 return(XML_IO_UNKNOWN);
875 return(0);
876 }
877 #endif /* LIBXML_ZLIB_ENABLED */
878
879 /************************************************************************
880 * *
881 * I/O for compressed file accesses *
882 * *
883 ************************************************************************/
884
885 #ifdef LIBXML_LZMA_ENABLED
886
887 #include "private/xzlib.h"
888
889 /**
890 * xmlXzfileRead:
891 * @context: the I/O context
892 * @buffer: where to drop data
893 * @len: number of bytes to write
894 *
895 * Read @len bytes to @buffer from the compressed I/O channel.
896 *
897 * Returns the number of bytes written
898 */
899 static int
xmlXzfileRead(void * context,char * buffer,int len)900 xmlXzfileRead (void * context, char * buffer, int len) {
901 int ret;
902
903 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
904 if (ret < 0)
905 return(-XML_IO_UNKNOWN);
906 return(ret);
907 }
908
909 /**
910 * xmlXzfileClose:
911 * @context: the I/O context
912 *
913 * Close a compressed I/O channel
914 */
915 static int
xmlXzfileClose(void * context)916 xmlXzfileClose (void * context) {
917 if (__libxml2_xzclose((xzFile) context) != LZMA_OK)
918 return(XML_IO_UNKNOWN);
919 return(0);
920 }
921 #endif /* LIBXML_LZMA_ENABLED */
922
923 /************************************************************************
924 * *
925 * I/O for HTTP file accesses *
926 * *
927 ************************************************************************/
928
929 #ifdef LIBXML_HTTP_ENABLED
930 /**
931 * xmlIOHTTPMatch:
932 * @filename: the URI for matching
933 *
934 * DEPRECATED: Internal function, don't use.
935 *
936 * check if the URI matches an HTTP one
937 *
938 * Returns 1 if matches, 0 otherwise
939 */
940 int
xmlIOHTTPMatch(const char * filename)941 xmlIOHTTPMatch (const char *filename) {
942 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
943 return(1);
944 return(0);
945 }
946
947 /**
948 * xmlIOHTTPOpen:
949 * @filename: the URI for matching
950 *
951 * DEPRECATED: Internal function, don't use.
952 *
953 * open an HTTP I/O channel
954 *
955 * Returns an I/O context or NULL in case of error
956 */
957 void *
xmlIOHTTPOpen(const char * filename)958 xmlIOHTTPOpen (const char *filename) {
959 return(xmlNanoHTTPOpen(filename, NULL));
960 }
961
962 #ifdef LIBXML_OUTPUT_ENABLED
963 /**
964 * xmlIOHTTPOpenW:
965 * @post_uri: The destination URI for the document
966 * @compression: The compression desired for the document.
967 *
968 * DEPRECATED: Support for HTTP POST has been removed.
969 *
970 * Returns NULL.
971 */
972 void *
xmlIOHTTPOpenW(const char * post_uri ATTRIBUTE_UNUSED,int compression ATTRIBUTE_UNUSED)973 xmlIOHTTPOpenW(const char *post_uri ATTRIBUTE_UNUSED,
974 int compression ATTRIBUTE_UNUSED)
975 {
976 return(NULL);
977 }
978 #endif /* LIBXML_OUTPUT_ENABLED */
979
980 /**
981 * xmlIOHTTPRead:
982 * @context: the I/O context
983 * @buffer: where to drop data
984 * @len: number of bytes to write
985 *
986 * DEPRECATED: Internal function, don't use.
987 *
988 * Read @len bytes to @buffer from the I/O channel.
989 *
990 * Returns the number of bytes written
991 */
992 int
xmlIOHTTPRead(void * context,char * buffer,int len)993 xmlIOHTTPRead(void * context, char * buffer, int len) {
994 if ((buffer == NULL) || (len < 0)) return(-1);
995 return(xmlNanoHTTPRead(context, &buffer[0], len));
996 }
997
998 /**
999 * xmlIOHTTPClose:
1000 * @context: the I/O context
1001 *
1002 * DEPRECATED: Internal function, don't use.
1003 *
1004 * Close an HTTP I/O channel
1005 *
1006 * Returns 0
1007 */
1008 int
xmlIOHTTPClose(void * context)1009 xmlIOHTTPClose (void * context) {
1010 xmlNanoHTTPClose(context);
1011 return 0;
1012 }
1013 #endif /* LIBXML_HTTP_ENABLED */
1014
1015 /************************************************************************
1016 * *
1017 * Input/output buffers *
1018 * *
1019 ************************************************************************/
1020
1021 static int
xmlIODefaultMatch(const char * filename ATTRIBUTE_UNUSED)1022 xmlIODefaultMatch(const char *filename ATTRIBUTE_UNUSED) {
1023 return(1);
1024 }
1025
1026 /**
1027 * xmlInputDefaultOpen:
1028 * @buf: input buffer to be filled
1029 * @filename: filename or URI
1030 * @flags: XML_INPUT flags
1031 *
1032 * Returns an xmlParserErrors code.
1033 */
1034 static int
xmlInputDefaultOpen(xmlParserInputBufferPtr buf,const char * filename,int flags)1035 xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename,
1036 int flags) {
1037 int ret;
1038 int fd;
1039
1040 /* Avoid unused variable warning */
1041 (void) flags;
1042
1043 #ifdef LIBXML_HTTP_ENABLED
1044 if (xmlIOHTTPMatch(filename)) {
1045 if ((flags & XML_INPUT_NETWORK) == 0)
1046 return(XML_IO_NETWORK_ATTEMPT);
1047
1048 buf->context = xmlIOHTTPOpen(filename);
1049
1050 if (buf->context != NULL) {
1051 buf->readcallback = xmlIOHTTPRead;
1052 buf->closecallback = xmlIOHTTPClose;
1053 return(XML_ERR_OK);
1054 }
1055 }
1056 #endif /* LIBXML_HTTP_ENABLED */
1057
1058 if (!xmlFileMatch(filename))
1059 return(XML_IO_ENOENT);
1060
1061 #ifdef LIBXML_LZMA_ENABLED
1062 if (flags & XML_INPUT_UNZIP) {
1063 xzFile xzStream;
1064
1065 ret = xmlFdOpen(filename, 0, &fd);
1066 if (ret != XML_ERR_OK)
1067 return(ret);
1068
1069 xzStream = __libxml2_xzdopen(filename, fd, "rb");
1070
1071 if (xzStream == NULL) {
1072 close(fd);
1073 } else {
1074 if (__libxml2_xzcompressed(xzStream) > 0) {
1075 buf->context = xzStream;
1076 buf->readcallback = xmlXzfileRead;
1077 buf->closecallback = xmlXzfileClose;
1078 buf->compressed = 1;
1079
1080 return(XML_ERR_OK);
1081 }
1082
1083 xmlXzfileClose(xzStream);
1084 }
1085 }
1086 #endif /* LIBXML_LZMA_ENABLED */
1087
1088 #ifdef LIBXML_ZLIB_ENABLED
1089 if (flags & XML_INPUT_UNZIP) {
1090 gzFile gzStream;
1091
1092 ret = xmlFdOpen(filename, 0, &fd);
1093 if (ret != XML_ERR_OK)
1094 return(ret);
1095
1096 gzStream = gzdopen(fd, "rb");
1097
1098 if (gzStream == NULL) {
1099 close(fd);
1100 } else {
1101 char buff4[4];
1102
1103 if ((gzread(gzStream, buff4, 4) > 0) &&
1104 (gzdirect(gzStream) == 0)) {
1105 gzrewind(gzStream);
1106
1107 buf->context = gzStream;
1108 buf->readcallback = xmlGzfileRead;
1109 buf->closecallback = xmlGzfileClose;
1110 buf->compressed = 1;
1111
1112 return(XML_ERR_OK);
1113 }
1114
1115 xmlGzfileClose(gzStream);
1116 }
1117 }
1118 #endif /* LIBXML_ZLIB_ENABLED */
1119
1120 ret = xmlFdOpen(filename, 0, &fd);
1121 if (ret != XML_ERR_OK)
1122 return(ret);
1123
1124 buf->context = (void *) (ptrdiff_t) fd;
1125 buf->readcallback = xmlFdRead;
1126 buf->closecallback = xmlFdClose;
1127 return(XML_ERR_OK);
1128 }
1129
1130 #ifdef LIBXML_OUTPUT_ENABLED
1131 /**
1132 * xmlOutputDefaultOpen:
1133 * @buf: input buffer to be filled
1134 * @filename: filename or URI
1135 * @compression: compression level or 0
1136 * @is_file_uri: whether filename is a file URI
1137 *
1138 * Returns an xmlParserErrors code.
1139 */
1140 static int
xmlOutputDefaultOpen(xmlOutputBufferPtr buf,const char * filename,int compression)1141 xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename,
1142 int compression) {
1143 int fd;
1144
1145 (void) compression;
1146
1147 if (!strcmp(filename, "-")) {
1148 fd = dup(STDOUT_FILENO);
1149
1150 if (fd < 0)
1151 return(xmlIOErr(errno));
1152 } else {
1153 int ret;
1154
1155 ret = xmlFdOpen(filename, /* write */ 1, &fd);
1156 if (ret != XML_ERR_OK)
1157 return(ret);
1158 }
1159
1160 #ifdef LIBXML_ZLIB_ENABLED
1161 if ((compression > 0) && (compression <= 9)) {
1162 gzFile gzStream;
1163 char mode[15];
1164
1165 snprintf(mode, sizeof(mode), "wb%d", compression);
1166 gzStream = gzdopen(fd, mode);
1167
1168 if (gzStream == NULL) {
1169 close(fd);
1170 return(XML_IO_UNKNOWN);
1171 }
1172
1173 buf->context = gzStream;
1174 buf->writecallback = xmlGzfileWrite;
1175 buf->closecallback = xmlGzfileClose;
1176
1177 return(XML_ERR_OK);
1178 }
1179 #endif /* LIBXML_ZLIB_ENABLED */
1180
1181 buf->context = (void *) (ptrdiff_t) fd;
1182 buf->writecallback = xmlFdWrite;
1183 buf->closecallback = xmlFdClose;
1184 return(XML_ERR_OK);
1185 }
1186 #endif
1187
1188 /**
1189 * xmlAllocParserInputBuffer:
1190 * @enc: the charset encoding if known (deprecated)
1191 *
1192 * Create a buffered parser input for progressive parsing.
1193 *
1194 * The encoding argument is deprecated and should be set to
1195 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1196 * xmlSwitchEncoding or xmlSwitchEncodingName later on.
1197 *
1198 * Returns the new parser input or NULL
1199 */
1200 xmlParserInputBufferPtr
xmlAllocParserInputBuffer(xmlCharEncoding enc)1201 xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1202 xmlParserInputBufferPtr ret;
1203
1204 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1205 if (ret == NULL) {
1206 return(NULL);
1207 }
1208 memset(ret, 0, sizeof(xmlParserInputBuffer));
1209 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
1210 if (ret->buffer == NULL) {
1211 xmlFree(ret);
1212 return(NULL);
1213 }
1214 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
1215 if (enc != XML_CHAR_ENCODING_NONE) {
1216 if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != 0) {
1217 /* We can't handle errors properly here. */
1218 xmlFreeParserInputBuffer(ret);
1219 return(NULL);
1220 }
1221 }
1222 if (ret->encoder != NULL)
1223 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
1224 else
1225 ret->raw = NULL;
1226 ret->readcallback = NULL;
1227 ret->closecallback = NULL;
1228 ret->context = NULL;
1229 ret->compressed = -1;
1230 ret->rawconsumed = 0;
1231
1232 return(ret);
1233 }
1234
1235 #ifdef LIBXML_OUTPUT_ENABLED
1236 /**
1237 * xmlAllocOutputBuffer:
1238 * @encoder: the encoding converter or NULL
1239 *
1240 * Create a buffered parser output
1241 *
1242 * Returns the new parser output or NULL
1243 */
1244 xmlOutputBufferPtr
xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder)1245 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
1246 xmlOutputBufferPtr ret;
1247
1248 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1249 if (ret == NULL) {
1250 return(NULL);
1251 }
1252 memset(ret, 0, sizeof(xmlOutputBuffer));
1253 ret->buffer = xmlBufCreate();
1254 if (ret->buffer == NULL) {
1255 xmlFree(ret);
1256 return(NULL);
1257 }
1258 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
1259
1260 ret->encoder = encoder;
1261 if (encoder != NULL) {
1262 ret->conv = xmlBufCreateSize(4000);
1263 if (ret->conv == NULL) {
1264 xmlBufFree(ret->buffer);
1265 xmlFree(ret);
1266 return(NULL);
1267 }
1268
1269 /*
1270 * This call is designed to initiate the encoder state
1271 */
1272 xmlCharEncOutput(ret, 1);
1273 } else
1274 ret->conv = NULL;
1275 ret->writecallback = NULL;
1276 ret->closecallback = NULL;
1277 ret->context = NULL;
1278 ret->written = 0;
1279
1280 return(ret);
1281 }
1282
1283 /**
1284 * xmlAllocOutputBufferInternal:
1285 * @encoder: the encoding converter or NULL
1286 *
1287 * Create a buffered parser output
1288 *
1289 * Returns the new parser output or NULL
1290 */
1291 xmlOutputBufferPtr
xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder)1292 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
1293 xmlOutputBufferPtr ret;
1294
1295 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1296 if (ret == NULL) {
1297 return(NULL);
1298 }
1299 memset(ret, 0, sizeof(xmlOutputBuffer));
1300 ret->buffer = xmlBufCreate();
1301 if (ret->buffer == NULL) {
1302 xmlFree(ret);
1303 return(NULL);
1304 }
1305
1306
1307 /*
1308 * For conversion buffers we use the special IO handling
1309 */
1310 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
1311
1312 ret->encoder = encoder;
1313 if (encoder != NULL) {
1314 ret->conv = xmlBufCreateSize(4000);
1315 if (ret->conv == NULL) {
1316 xmlBufFree(ret->buffer);
1317 xmlFree(ret);
1318 return(NULL);
1319 }
1320
1321 /*
1322 * This call is designed to initiate the encoder state
1323 */
1324 xmlCharEncOutput(ret, 1);
1325 } else
1326 ret->conv = NULL;
1327 ret->writecallback = NULL;
1328 ret->closecallback = NULL;
1329 ret->context = NULL;
1330 ret->written = 0;
1331
1332 return(ret);
1333 }
1334
1335 #endif /* LIBXML_OUTPUT_ENABLED */
1336
1337 /**
1338 * xmlFreeParserInputBuffer:
1339 * @in: a buffered parser input
1340 *
1341 * Free up the memory used by a buffered parser input
1342 */
1343 void
xmlFreeParserInputBuffer(xmlParserInputBufferPtr in)1344 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1345 if (in == NULL) return;
1346
1347 if (in->raw) {
1348 xmlBufFree(in->raw);
1349 in->raw = NULL;
1350 }
1351 if (in->encoder != NULL) {
1352 xmlCharEncCloseFunc(in->encoder);
1353 }
1354 if (in->closecallback != NULL) {
1355 in->closecallback(in->context);
1356 }
1357 if (in->buffer != NULL) {
1358 xmlBufFree(in->buffer);
1359 in->buffer = NULL;
1360 }
1361
1362 xmlFree(in);
1363 }
1364
1365 #ifdef LIBXML_OUTPUT_ENABLED
1366 /**
1367 * xmlOutputBufferClose:
1368 * @out: a buffered output
1369 *
1370 * flushes and close the output I/O channel
1371 * and free up all the associated resources
1372 *
1373 * Returns the number of byte written or a negative xmlParserErrors
1374 * code in case of error.
1375 */
1376 int
xmlOutputBufferClose(xmlOutputBufferPtr out)1377 xmlOutputBufferClose(xmlOutputBufferPtr out)
1378 {
1379 int ret;
1380
1381 if (out == NULL)
1382 return (-1);
1383
1384 if (out->writecallback != NULL)
1385 xmlOutputBufferFlush(out);
1386
1387 if (out->closecallback != NULL) {
1388 int code = out->closecallback(out->context);
1389
1390 if ((code != XML_ERR_OK) && (out->error == XML_ERR_OK)) {
1391 if (code < 0)
1392 out->error = XML_IO_UNKNOWN;
1393 else
1394 out->error = code;
1395 }
1396 }
1397
1398 if (out->error != XML_ERR_OK)
1399 ret = -out->error;
1400 else
1401 ret = out->written;
1402
1403 if (out->conv) {
1404 xmlBufFree(out->conv);
1405 out->conv = NULL;
1406 }
1407 if (out->encoder != NULL) {
1408 xmlCharEncCloseFunc(out->encoder);
1409 }
1410 if (out->buffer != NULL) {
1411 xmlBufFree(out->buffer);
1412 out->buffer = NULL;
1413 }
1414
1415 xmlFree(out);
1416
1417 return(ret);
1418 }
1419 #endif /* LIBXML_OUTPUT_ENABLED */
1420
1421 /**
1422 * xmlParserInputBufferCreateUrl:
1423 * @URI: the filename or URI
1424 * @enc: encoding enum (deprecated)
1425 * @flags: XML_INPUT flags
1426 * @out: pointer to resulting input buffer
1427 *
1428 * Returns an xmlParserErrors code.
1429 */
1430 int
xmlParserInputBufferCreateUrl(const char * URI,xmlCharEncoding enc,int flags,xmlParserInputBufferPtr * out)1431 xmlParserInputBufferCreateUrl(const char *URI, xmlCharEncoding enc,
1432 int flags, xmlParserInputBufferPtr *out) {
1433 xmlParserInputBufferPtr buf;
1434 int ret;
1435 int i;
1436
1437 *out = NULL;
1438 if (URI == NULL)
1439 return(XML_ERR_ARGUMENT);
1440
1441 /*
1442 * Allocate the Input buffer front-end.
1443 */
1444 buf = xmlAllocParserInputBuffer(enc);
1445 if (buf == NULL)
1446 return(XML_ERR_NO_MEMORY);
1447
1448 /*
1449 * Try to find one of the input accept method accepting that scheme
1450 * Go in reverse to give precedence to user defined handlers.
1451 */
1452 ret = XML_IO_ENOENT;
1453 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
1454 xmlInputCallback *cb = &xmlInputCallbackTable[i];
1455
1456 if (cb->matchcallback == xmlIODefaultMatch) {
1457 ret = xmlInputDefaultOpen(buf, URI, flags);
1458
1459 if ((ret == XML_ERR_OK) || (ret != XML_IO_ENOENT))
1460 break;
1461 } else if ((cb->matchcallback != NULL) &&
1462 (cb->matchcallback(URI) != 0)) {
1463 buf->context = cb->opencallback(URI);
1464 if (buf->context != NULL) {
1465 buf->readcallback = cb->readcallback;
1466 buf->closecallback = cb->closecallback;
1467 ret = XML_ERR_OK;
1468 break;
1469 }
1470 }
1471 }
1472 if (ret != XML_ERR_OK) {
1473 xmlFreeParserInputBuffer(buf);
1474 *out = NULL;
1475 return(ret);
1476 }
1477
1478 *out = buf;
1479 return(ret);
1480 }
1481
1482 xmlParserInputBufferPtr
__xmlParserInputBufferCreateFilename(const char * URI,xmlCharEncoding enc)1483 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1484 xmlParserInputBufferPtr ret;
1485
1486 xmlParserInputBufferCreateUrl(URI, enc, 0, &ret);
1487 return(ret);
1488 }
1489
1490 /**
1491 * xmlParserInputBufferCreateFilename:
1492 * @URI: a C string containing the URI or filename
1493 * @enc: the charset encoding if known
1494 *
1495 * Create a buffered parser input for the progressive parsing of a file
1496 * Automatic support for ZLIB/Compress compressed document is provided
1497 * by default if found at compile-time.
1498 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1499 *
1500 * Returns the new parser input or NULL
1501 */
1502 xmlParserInputBufferPtr
xmlParserInputBufferCreateFilename(const char * URI,xmlCharEncoding enc)1503 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1504 xmlParserInputBufferPtr ret;
1505
1506 if (xmlParserInputBufferCreateFilenameValue != NULL)
1507 return(xmlParserInputBufferCreateFilenameValue(URI, enc));
1508
1509 xmlParserInputBufferCreateUrl(URI, enc, 0, &ret);
1510 return(ret);
1511 }
1512
1513 #ifdef LIBXML_OUTPUT_ENABLED
1514 xmlOutputBufferPtr
__xmlOutputBufferCreateFilename(const char * URI,xmlCharEncodingHandlerPtr encoder,int compression)1515 __xmlOutputBufferCreateFilename(const char *URI,
1516 xmlCharEncodingHandlerPtr encoder,
1517 int compression) {
1518 xmlOutputBufferPtr ret;
1519 xmlURIPtr puri;
1520 int i = 0;
1521 char *unescaped = NULL;
1522
1523 if (URI == NULL)
1524 return(NULL);
1525
1526 puri = xmlParseURI(URI);
1527 if (puri != NULL) {
1528 /*
1529 * try to limit the damages of the URI unescaping code.
1530 */
1531 if (puri->scheme == NULL) {
1532 unescaped = xmlURIUnescapeString(URI, 0, NULL);
1533 if (unescaped == NULL) {
1534 xmlFreeURI(puri);
1535 return(NULL);
1536 }
1537 URI = unescaped;
1538 }
1539 xmlFreeURI(puri);
1540 }
1541
1542 /*
1543 * Allocate the Output buffer front-end.
1544 */
1545 ret = xmlAllocOutputBufferInternal(encoder);
1546 if (ret == NULL) {
1547 xmlFree(unescaped);
1548 return(NULL);
1549 }
1550
1551 /*
1552 * Try to find one of the output accept method accepting that scheme
1553 * Go in reverse to give precedence to user defined handlers.
1554 */
1555 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
1556 xmlOutputCallback *cb = &xmlOutputCallbackTable[i];
1557 int code;
1558
1559 if (cb->matchcallback == xmlIODefaultMatch) {
1560 code = xmlOutputDefaultOpen(ret, URI, compression);
1561 /* TODO: Handle other errors */
1562 if (code == XML_ERR_OK)
1563 break;
1564 } else if ((cb->matchcallback != NULL) &&
1565 (cb->matchcallback(URI) != 0)) {
1566 ret->context = cb->opencallback(URI);
1567 if (ret->context != NULL) {
1568 ret->writecallback = cb->writecallback;
1569 ret->closecallback = cb->closecallback;
1570 break;
1571 }
1572 }
1573 }
1574
1575 if (ret->context == NULL) {
1576 xmlOutputBufferClose(ret);
1577 ret = NULL;
1578 }
1579
1580 xmlFree(unescaped);
1581 return(ret);
1582 }
1583
1584 /**
1585 * xmlOutputBufferCreateFilename:
1586 * @URI: a C string containing the URI or filename
1587 * @encoder: the encoding converter or NULL
1588 * @compression: the compression ration (0 none, 9 max).
1589 *
1590 * Create a buffered output for the progressive saving of a file
1591 * If filename is "-' then we use stdout as the output.
1592 * Automatic support for ZLIB/Compress compressed document is provided
1593 * by default if found at compile-time.
1594 * TODO: currently if compression is set, the library only support
1595 * writing to a local file.
1596 *
1597 * Returns the new output or NULL
1598 */
1599 xmlOutputBufferPtr
xmlOutputBufferCreateFilename(const char * URI,xmlCharEncodingHandlerPtr encoder,int compression ATTRIBUTE_UNUSED)1600 xmlOutputBufferCreateFilename(const char *URI,
1601 xmlCharEncodingHandlerPtr encoder,
1602 int compression ATTRIBUTE_UNUSED) {
1603 if ((xmlOutputBufferCreateFilenameValue)) {
1604 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
1605 }
1606 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
1607 }
1608 #endif /* LIBXML_OUTPUT_ENABLED */
1609
1610 /**
1611 * xmlParserInputBufferCreateFile:
1612 * @file: a FILE*
1613 * @enc: the charset encoding if known (deprecated)
1614 *
1615 * Create a buffered parser input for the progressive parsing of a FILE *
1616 * buffered C I/O
1617 *
1618 * The encoding argument is deprecated and should be set to
1619 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1620 * xmlSwitchEncoding or xmlSwitchEncodingName later on.
1621 *
1622 * Returns the new parser input or NULL
1623 */
1624 xmlParserInputBufferPtr
xmlParserInputBufferCreateFile(FILE * file,xmlCharEncoding enc)1625 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1626 xmlParserInputBufferPtr ret;
1627
1628 if (file == NULL) return(NULL);
1629
1630 ret = xmlAllocParserInputBuffer(enc);
1631 if (ret != NULL) {
1632 ret->context = file;
1633 ret->readcallback = xmlFileRead;
1634 ret->closecallback = NULL;
1635 }
1636
1637 return(ret);
1638 }
1639
1640 #ifdef LIBXML_OUTPUT_ENABLED
1641 /**
1642 * xmlOutputBufferCreateFile:
1643 * @file: a FILE*
1644 * @encoder: the encoding converter or NULL
1645 *
1646 * Create a buffered output for the progressive saving to a FILE *
1647 * buffered C I/O
1648 *
1649 * Returns the new parser output or NULL
1650 */
1651 xmlOutputBufferPtr
xmlOutputBufferCreateFile(FILE * file,xmlCharEncodingHandlerPtr encoder)1652 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
1653 xmlOutputBufferPtr ret;
1654
1655 if (file == NULL) return(NULL);
1656
1657 ret = xmlAllocOutputBufferInternal(encoder);
1658 if (ret != NULL) {
1659 ret->context = file;
1660 ret->writecallback = xmlFileWrite;
1661 ret->closecallback = xmlFileFlush;
1662 }
1663
1664 return(ret);
1665 }
1666
1667 /**
1668 * xmlOutputBufferCreateBuffer:
1669 * @buffer: a xmlBufferPtr
1670 * @encoder: the encoding converter or NULL
1671 *
1672 * Create a buffered output for the progressive saving to a xmlBuffer
1673 *
1674 * Returns the new parser output or NULL
1675 */
1676 xmlOutputBufferPtr
xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,xmlCharEncodingHandlerPtr encoder)1677 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
1678 xmlCharEncodingHandlerPtr encoder) {
1679 xmlOutputBufferPtr ret;
1680
1681 if (buffer == NULL) return(NULL);
1682
1683 ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
1684 encoder);
1685
1686 return(ret);
1687 }
1688
1689 /**
1690 * xmlOutputBufferGetContent:
1691 * @out: an xmlOutputBufferPtr
1692 *
1693 * Gives a pointer to the data currently held in the output buffer
1694 *
1695 * Returns a pointer to the data or NULL in case of error
1696 */
1697 const xmlChar *
xmlOutputBufferGetContent(xmlOutputBufferPtr out)1698 xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
1699 if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
1700 return(NULL);
1701
1702 return(xmlBufContent(out->buffer));
1703 }
1704
1705 /**
1706 * xmlOutputBufferGetSize:
1707 * @out: an xmlOutputBufferPtr
1708 *
1709 * Gives the length of the data currently held in the output buffer
1710 *
1711 * Returns 0 in case or error or no data is held, the size otherwise
1712 */
1713 size_t
xmlOutputBufferGetSize(xmlOutputBufferPtr out)1714 xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
1715 if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
1716 return(0);
1717
1718 return(xmlBufUse(out->buffer));
1719 }
1720
1721
1722 #endif /* LIBXML_OUTPUT_ENABLED */
1723
1724 /**
1725 * xmlParserInputBufferCreateFd:
1726 * @fd: a file descriptor number
1727 * @enc: the charset encoding if known (deprecated)
1728 *
1729 * Create a buffered parser input for the progressive parsing for the input
1730 * from a file descriptor
1731 *
1732 * The encoding argument is deprecated and should be set to
1733 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1734 * xmlSwitchEncoding or xmlSwitchEncodingName later on.
1735 *
1736 * Returns the new parser input or NULL
1737 */
1738 xmlParserInputBufferPtr
xmlParserInputBufferCreateFd(int fd,xmlCharEncoding enc)1739 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1740 xmlParserInputBufferPtr ret;
1741
1742 if (fd < 0) return(NULL);
1743
1744 ret = xmlAllocParserInputBuffer(enc);
1745 if (ret != NULL) {
1746 ret->context = (void *) (ptrdiff_t) fd;
1747 ret->readcallback = xmlFdRead;
1748 }
1749
1750 return(ret);
1751 }
1752
1753 typedef struct {
1754 char *mem;
1755 const char *cur;
1756 size_t size;
1757 } xmlMemIOCtxt;
1758
1759 static int
xmlMemRead(void * vctxt,char * buf,int size)1760 xmlMemRead(void *vctxt, char *buf, int size) {
1761 xmlMemIOCtxt *ctxt = vctxt;
1762
1763 if ((size_t) size > ctxt->size)
1764 size = ctxt->size;
1765
1766 memcpy(buf, ctxt->cur, size);
1767 ctxt->cur += size;
1768 ctxt->size -= size;
1769
1770 return size;
1771 }
1772
1773 static int
xmlMemClose(void * vctxt)1774 xmlMemClose(void *vctxt) {
1775 xmlMemIOCtxt *ctxt = vctxt;
1776
1777 if (ctxt->mem != NULL)
1778 xmlFree(ctxt->mem);
1779 xmlFree(ctxt);
1780 return(0);
1781 }
1782
1783 /**
1784 * xmlNewInputBufferMemory:
1785 * @mem: memory buffer
1786 * @size: size of buffer
1787 * @flags: flags
1788 * @enc: the charset encoding if known (deprecated)
1789 *
1790 * Create an input buffer for memory.
1791 *
1792 * Returns the new input buffer or NULL.
1793 */
1794 xmlParserInputBufferPtr
xmlNewInputBufferMemory(const void * mem,size_t size,int flags,xmlCharEncoding enc)1795 xmlNewInputBufferMemory(const void *mem, size_t size, int flags,
1796 xmlCharEncoding enc) {
1797 xmlParserInputBufferPtr ret;
1798 xmlMemIOCtxt *ctxt;
1799 char *copy = NULL;
1800
1801 if ((flags & XML_INPUT_BUF_STATIC) == 0) {
1802 if (size + 1 == 0)
1803 return(NULL);
1804 copy = xmlMalloc(size + 1);
1805 if (copy == NULL)
1806 return(NULL);
1807 memcpy(copy, mem, size);
1808 copy[size] = 0;
1809
1810 mem = copy;
1811 }
1812
1813 ret = xmlAllocParserInputBuffer(enc);
1814 if (ret == NULL) {
1815 xmlFree(copy);
1816 return(NULL);
1817 }
1818
1819 ctxt = xmlMalloc(sizeof(*ctxt));
1820 if (ctxt == NULL) {
1821 xmlFreeParserInputBuffer(ret);
1822 xmlFree(copy);
1823 return(NULL);
1824 }
1825
1826 ctxt->mem = copy;
1827 ctxt->cur = mem;
1828 ctxt->size = size;
1829
1830 ret->context = ctxt;
1831 ret->readcallback = xmlMemRead;
1832 ret->closecallback = xmlMemClose;
1833
1834 return(ret);
1835 }
1836
1837 /**
1838 * xmlParserInputBufferCreateMem:
1839 * @mem: the memory input
1840 * @size: the length of the memory block
1841 * @enc: the charset encoding if known (deprecated)
1842 *
1843 * Create a parser input buffer for parsing from a memory area.
1844 *
1845 * This function makes a copy of the whole input buffer. If you are sure
1846 * that the contents of the buffer will remain valid until the document
1847 * was parsed, you can avoid the copy by using
1848 * xmlParserInputBufferCreateStatic.
1849 *
1850 * The encoding argument is deprecated and should be set to
1851 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1852 * xmlSwitchEncoding or xmlSwitchEncodingName later on.
1853 *
1854 * Returns the new parser input or NULL in case of error.
1855 */
1856 xmlParserInputBufferPtr
xmlParserInputBufferCreateMem(const char * mem,int size,xmlCharEncoding enc)1857 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
1858 if ((mem == NULL) || (size < 0))
1859 return(NULL);
1860
1861 return(xmlNewInputBufferMemory(mem, size, 0, enc));
1862 }
1863
1864 /**
1865 * xmlParserInputBufferCreateStatic:
1866 * @mem: the memory input
1867 * @size: the length of the memory block
1868 * @enc: the charset encoding if known
1869 *
1870 * Create a parser input buffer for parsing from a memory area.
1871 *
1872 * This functions assumes that the contents of the input buffer remain
1873 * valid until the document was parsed. Use xmlParserInputBufferCreateMem
1874 * otherwise.
1875 *
1876 * The encoding argument is deprecated and should be set to
1877 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1878 * xmlSwitchEncoding or xmlSwitchEncodingName later on.
1879 *
1880 * Returns the new parser input or NULL in case of error.
1881 */
1882 xmlParserInputBufferPtr
xmlParserInputBufferCreateStatic(const char * mem,int size,xmlCharEncoding enc)1883 xmlParserInputBufferCreateStatic(const char *mem, int size,
1884 xmlCharEncoding enc) {
1885 if ((mem == NULL) || (size < 0))
1886 return(NULL);
1887
1888 return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc));
1889 }
1890
1891 typedef struct {
1892 const char *str;
1893 } xmlStringIOCtxt;
1894
1895 static int
xmlStringRead(void * vctxt,char * buf,int size)1896 xmlStringRead(void *vctxt, char *buf, int size) {
1897 xmlStringIOCtxt *ctxt = vctxt;
1898 const char *zero;
1899 size_t len;
1900
1901 zero = memchr(ctxt->str, 0, size);
1902 len = zero ? zero - ctxt->str : size;
1903
1904 memcpy(buf, ctxt->str, len);
1905 ctxt->str += len;
1906
1907 return(len);
1908 }
1909
1910 static int
xmlStringClose(void * vctxt)1911 xmlStringClose(void *vctxt) {
1912 xmlFree(vctxt);
1913 return(0);
1914 }
1915
1916 /**
1917 * xmlNewInputBufferString:
1918 * @str: C string
1919 * @flags: flags
1920 *
1921 * Create an input buffer for a null-teriminated C string.
1922 *
1923 * Returns the new input buffer or NULL.
1924 */
1925 xmlParserInputBufferPtr
xmlNewInputBufferString(const char * str,int flags)1926 xmlNewInputBufferString(const char *str, int flags) {
1927 xmlParserInputBufferPtr ret;
1928 xmlStringIOCtxt *ctxt;
1929
1930 if ((flags & XML_INPUT_BUF_STATIC) == 0)
1931 return(xmlNewInputBufferMemory(str, strlen(str), flags,
1932 XML_CHAR_ENCODING_NONE));
1933
1934 ret = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
1935 if (ret == NULL)
1936 return(NULL);
1937
1938 ctxt = xmlMalloc(sizeof(*ctxt));
1939 if (ctxt == NULL) {
1940 xmlFreeParserInputBuffer(ret);
1941 return(NULL);
1942 }
1943
1944 ctxt->str = str;
1945
1946 ret->context = ctxt;
1947 ret->readcallback = xmlStringRead;
1948 ret->closecallback = xmlStringClose;
1949
1950 return(ret);
1951 }
1952
1953 #ifdef LIBXML_OUTPUT_ENABLED
1954 /**
1955 * xmlOutputBufferCreateFd:
1956 * @fd: a file descriptor number
1957 * @encoder: the encoding converter or NULL
1958 *
1959 * Create a buffered output for the progressive saving
1960 * to a file descriptor
1961 *
1962 * Returns the new parser output or NULL
1963 */
1964 xmlOutputBufferPtr
xmlOutputBufferCreateFd(int fd,xmlCharEncodingHandlerPtr encoder)1965 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
1966 xmlOutputBufferPtr ret;
1967
1968 if (fd < 0) return(NULL);
1969
1970 ret = xmlAllocOutputBufferInternal(encoder);
1971 if (ret != NULL) {
1972 ret->context = (void *) (ptrdiff_t) fd;
1973 ret->writecallback = xmlFdWrite;
1974 ret->closecallback = NULL;
1975 }
1976
1977 return(ret);
1978 }
1979 #endif /* LIBXML_OUTPUT_ENABLED */
1980
1981 /**
1982 * xmlParserInputBufferCreateIO:
1983 * @ioread: an I/O read function
1984 * @ioclose: an I/O close function
1985 * @ioctx: an I/O handler
1986 * @enc: the charset encoding if known (deprecated)
1987 *
1988 * Create a buffered parser input for the progressive parsing for the input
1989 * from an I/O handler
1990 *
1991 * The encoding argument is deprecated and should be set to
1992 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1993 * xmlSwitchEncoding or xmlSwitchEncodingName later on.
1994 *
1995 * Returns the new parser input or NULL
1996 */
1997 xmlParserInputBufferPtr
xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx,xmlCharEncoding enc)1998 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
1999 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2000 xmlParserInputBufferPtr ret;
2001
2002 if (ioread == NULL) return(NULL);
2003
2004 ret = xmlAllocParserInputBuffer(enc);
2005 if (ret != NULL) {
2006 ret->context = (void *) ioctx;
2007 ret->readcallback = ioread;
2008 ret->closecallback = ioclose;
2009 }
2010
2011 return(ret);
2012 }
2013
2014 #ifdef LIBXML_OUTPUT_ENABLED
2015 /**
2016 * xmlOutputBufferCreateIO:
2017 * @iowrite: an I/O write function
2018 * @ioclose: an I/O close function
2019 * @ioctx: an I/O handler
2020 * @encoder: the charset encoding if known
2021 *
2022 * Create a buffered output for the progressive saving
2023 * to an I/O handler
2024 *
2025 * Returns the new parser output or NULL
2026 */
2027 xmlOutputBufferPtr
xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,xmlOutputCloseCallback ioclose,void * ioctx,xmlCharEncodingHandlerPtr encoder)2028 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2029 xmlOutputCloseCallback ioclose, void *ioctx,
2030 xmlCharEncodingHandlerPtr encoder) {
2031 xmlOutputBufferPtr ret;
2032
2033 if (iowrite == NULL) return(NULL);
2034
2035 ret = xmlAllocOutputBufferInternal(encoder);
2036 if (ret != NULL) {
2037 ret->context = (void *) ioctx;
2038 ret->writecallback = iowrite;
2039 ret->closecallback = ioclose;
2040 }
2041
2042 return(ret);
2043 }
2044 #endif /* LIBXML_OUTPUT_ENABLED */
2045
2046 /**
2047 * xmlParserInputBufferCreateFilenameDefault:
2048 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2049 *
2050 * DEPRECATED: Use xmlCtxtSetResourceLoader or similar functions.
2051 *
2052 * Registers a callback for URI input file handling
2053 *
2054 * Returns the old value of the registration function
2055 */
2056 xmlParserInputBufferCreateFilenameFunc
xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)2057 xmlParserInputBufferCreateFilenameDefault(
2058 xmlParserInputBufferCreateFilenameFunc func)
2059 {
2060 xmlParserInputBufferCreateFilenameFunc old;
2061
2062 old = xmlParserInputBufferCreateFilenameValue;
2063 if (old == NULL)
2064 old = __xmlParserInputBufferCreateFilename;
2065
2066 if (func == __xmlParserInputBufferCreateFilename)
2067 func = NULL;
2068 xmlParserInputBufferCreateFilenameValue = func;
2069 return(old);
2070 }
2071
2072 /**
2073 * xmlOutputBufferCreateFilenameDefault:
2074 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2075 *
2076 * Registers a callback for URI output file handling
2077 *
2078 * Returns the old value of the registration function
2079 */
2080 xmlOutputBufferCreateFilenameFunc
xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)2081 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2082 {
2083 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2084 #ifdef LIBXML_OUTPUT_ENABLED
2085 if (old == NULL) {
2086 old = __xmlOutputBufferCreateFilename;
2087 }
2088 #endif
2089 xmlOutputBufferCreateFilenameValue = func;
2090 return(old);
2091 }
2092
2093 /**
2094 * xmlParserInputBufferPush:
2095 * @in: a buffered parser input
2096 * @len: the size in bytes of the array.
2097 * @buf: an char array
2098 *
2099 * Push the content of the arry in the input buffer
2100 * This routine handle the I18N transcoding to internal UTF-8
2101 * This is used when operating the parser in progressive (push) mode.
2102 *
2103 * Returns the number of chars read and stored in the buffer, or -1
2104 * in case of error.
2105 */
2106 int
xmlParserInputBufferPush(xmlParserInputBufferPtr in,int len,const char * buf)2107 xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2108 int len, const char *buf) {
2109 int nbchars = 0;
2110 int ret;
2111
2112 if (len < 0) return(0);
2113 if ((in == NULL) || (in->error)) return(-1);
2114 if (in->encoder != NULL) {
2115 /*
2116 * Store the data in the incoming raw buffer
2117 */
2118 if (in->raw == NULL) {
2119 in->raw = xmlBufCreate();
2120 if (in->raw == NULL) {
2121 in->error = XML_ERR_NO_MEMORY;
2122 return(-1);
2123 }
2124 }
2125 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
2126 if (ret != 0) {
2127 in->error = XML_ERR_NO_MEMORY;
2128 return(-1);
2129 }
2130
2131 /*
2132 * convert as much as possible to the parser reading buffer.
2133 */
2134 nbchars = xmlCharEncInput(in);
2135 if (nbchars < 0)
2136 return(-1);
2137 } else {
2138 nbchars = len;
2139 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
2140 if (ret != 0) {
2141 in->error = XML_ERR_NO_MEMORY;
2142 return(-1);
2143 }
2144 }
2145 return(nbchars);
2146 }
2147
2148 /**
2149 * endOfInput:
2150 *
2151 * When reading from an Input channel indicated end of file or error
2152 * don't reread from it again.
2153 */
2154 static int
endOfInput(void * context ATTRIBUTE_UNUSED,char * buffer ATTRIBUTE_UNUSED,int len ATTRIBUTE_UNUSED)2155 endOfInput (void * context ATTRIBUTE_UNUSED,
2156 char * buffer ATTRIBUTE_UNUSED,
2157 int len ATTRIBUTE_UNUSED) {
2158 return(0);
2159 }
2160
2161 /**
2162 * xmlParserInputBufferGrow:
2163 * @in: a buffered parser input
2164 * @len: indicative value of the amount of chars to read
2165 *
2166 * Grow up the content of the input buffer, the old data are preserved
2167 * This routine handle the I18N transcoding to internal UTF-8
2168 * This routine is used when operating the parser in normal (pull) mode
2169 *
2170 * TODO: one should be able to remove one extra copy by copying directly
2171 * onto in->buffer or in->raw
2172 *
2173 * Returns the number of chars read and stored in the buffer, or -1
2174 * in case of error.
2175 */
2176 int
xmlParserInputBufferGrow(xmlParserInputBufferPtr in,int len)2177 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
2178 xmlBufPtr buf;
2179 int res = 0;
2180
2181 if ((in == NULL) || (in->error)) return(-1);
2182 if ((len <= MINLEN) && (len != 4))
2183 len = MINLEN;
2184
2185 if (in->encoder == NULL) {
2186 if (in->readcallback == NULL)
2187 return(0);
2188 buf = in->buffer;
2189 } else {
2190 if (in->raw == NULL) {
2191 in->raw = xmlBufCreate();
2192 }
2193 buf = in->raw;
2194 }
2195
2196 /*
2197 * Call the read method for this I/O type.
2198 */
2199 if (in->readcallback != NULL) {
2200 if (xmlBufGrow(buf, len + 1) < 0) {
2201 in->error = XML_ERR_NO_MEMORY;
2202 return(-1);
2203 }
2204
2205 res = in->readcallback(in->context, (char *)xmlBufEnd(buf), len);
2206 if (res <= 0)
2207 in->readcallback = endOfInput;
2208 if (res < 0) {
2209 if (res == -1)
2210 in->error = XML_IO_UNKNOWN;
2211 else
2212 in->error = -res;
2213 return(-1);
2214 }
2215
2216 if (xmlBufAddLen(buf, res) < 0) {
2217 in->error = XML_ERR_NO_MEMORY;
2218 return(-1);
2219 }
2220 }
2221
2222 /*
2223 * try to establish compressed status of input if not done already
2224 */
2225 if (in->compressed == -1) {
2226 #ifdef LIBXML_LZMA_ENABLED
2227 if (in->readcallback == xmlXzfileRead)
2228 in->compressed = __libxml2_xzcompressed(in->context);
2229 #endif
2230 }
2231
2232 if (in->encoder != NULL) {
2233 res = xmlCharEncInput(in);
2234 if (res < 0)
2235 return(-1);
2236 }
2237 return(res);
2238 }
2239
2240 /**
2241 * xmlParserInputBufferRead:
2242 * @in: a buffered parser input
2243 * @len: indicative value of the amount of chars to read
2244 *
2245 * Refresh the content of the input buffer, the old data are considered
2246 * consumed
2247 * This routine handle the I18N transcoding to internal UTF-8
2248 *
2249 * Returns the number of chars read and stored in the buffer, or -1
2250 * in case of error.
2251 */
2252 int
xmlParserInputBufferRead(xmlParserInputBufferPtr in,int len)2253 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
2254 return(xmlParserInputBufferGrow(in, len));
2255 }
2256
2257 #ifdef LIBXML_OUTPUT_ENABLED
2258 /**
2259 * xmlOutputBufferWrite:
2260 * @out: a buffered parser output
2261 * @len: the size in bytes of the array.
2262 * @buf: an char array
2263 *
2264 * Write the content of the array in the output I/O buffer
2265 * This routine handle the I18N transcoding from internal UTF-8
2266 * The buffer is lossless, i.e. will store in case of partial
2267 * or delayed writes.
2268 *
2269 * Returns the number of chars immediately written, or -1
2270 * in case of error.
2271 */
2272 int
xmlOutputBufferWrite(xmlOutputBufferPtr out,int len,const char * buf)2273 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
2274 int nbchars = 0; /* number of chars to output to I/O */
2275 int ret; /* return from function call */
2276 int written = 0; /* number of char written to I/O so far */
2277 int chunk; /* number of byte current processed from buf */
2278
2279 if ((out == NULL) || (out->error)) return(-1);
2280 if (len < 0) return(0);
2281 if (out->error) return(-1);
2282
2283 do {
2284 chunk = len;
2285 if (chunk > 4 * MINLEN)
2286 chunk = 4 * MINLEN;
2287
2288 /*
2289 * first handle encoding stuff.
2290 */
2291 if (out->encoder != NULL) {
2292 /*
2293 * Store the data in the incoming raw buffer
2294 */
2295 if (out->conv == NULL) {
2296 out->conv = xmlBufCreate();
2297 if (out->conv == NULL) {
2298 out->error = XML_ERR_NO_MEMORY;
2299 return(-1);
2300 }
2301 }
2302 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
2303 if (ret != 0) {
2304 out->error = XML_ERR_NO_MEMORY;
2305 return(-1);
2306 }
2307
2308 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
2309 goto done;
2310
2311 /*
2312 * convert as much as possible to the parser reading buffer.
2313 */
2314 ret = xmlCharEncOutput(out, 0);
2315 if (ret < 0)
2316 return(-1);
2317 if (out->writecallback)
2318 nbchars = xmlBufUse(out->conv);
2319 else
2320 nbchars = ret >= 0 ? ret : 0;
2321 } else {
2322 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
2323 if (ret != 0) {
2324 out->error = XML_ERR_NO_MEMORY;
2325 return(-1);
2326 }
2327 if (out->writecallback)
2328 nbchars = xmlBufUse(out->buffer);
2329 else
2330 nbchars = chunk;
2331 }
2332 buf += chunk;
2333 len -= chunk;
2334
2335 if (out->writecallback) {
2336 if ((nbchars < MINLEN) && (len <= 0))
2337 goto done;
2338
2339 /*
2340 * second write the stuff to the I/O channel
2341 */
2342 if (out->encoder != NULL) {
2343 ret = out->writecallback(out->context,
2344 (const char *)xmlBufContent(out->conv), nbchars);
2345 if (ret >= 0)
2346 xmlBufShrink(out->conv, ret);
2347 } else {
2348 ret = out->writecallback(out->context,
2349 (const char *)xmlBufContent(out->buffer), nbchars);
2350 if (ret >= 0)
2351 xmlBufShrink(out->buffer, ret);
2352 }
2353 if (ret < 0) {
2354 out->error = (ret == -1) ? XML_IO_WRITE : -ret;
2355 return(ret);
2356 }
2357 if (out->written > INT_MAX - ret)
2358 out->written = INT_MAX;
2359 else
2360 out->written += ret;
2361 }
2362 written += nbchars;
2363 } while (len > 0);
2364
2365 done:
2366 return(written);
2367 }
2368
2369 /**
2370 * xmlEscapeContent:
2371 * @out: a pointer to an array of bytes to store the result
2372 * @outlen: the length of @out
2373 * @in: a pointer to an array of unescaped UTF-8 bytes
2374 * @inlen: the length of @in
2375 *
2376 * Take a block of UTF-8 chars in and escape them.
2377 * Returns 0 if success, or -1 otherwise
2378 * The value of @inlen after return is the number of octets consumed
2379 * if the return value is positive, else unpredictable.
2380 * The value of @outlen after return is the number of octets consumed.
2381 */
2382 static int
xmlEscapeContent(unsigned char * out,int * outlen,const xmlChar * in,int * inlen)2383 xmlEscapeContent(unsigned char* out, int *outlen,
2384 const xmlChar* in, int *inlen) {
2385 unsigned char* outstart = out;
2386 const unsigned char* base = in;
2387 unsigned char* outend = out + *outlen;
2388 const unsigned char* inend;
2389
2390 inend = in + (*inlen);
2391
2392 while ((in < inend) && (out < outend)) {
2393 if (*in == '<') {
2394 if (outend - out < 4) break;
2395 *out++ = '&';
2396 *out++ = 'l';
2397 *out++ = 't';
2398 *out++ = ';';
2399 } else if (*in == '>') {
2400 if (outend - out < 4) break;
2401 *out++ = '&';
2402 *out++ = 'g';
2403 *out++ = 't';
2404 *out++ = ';';
2405 } else if (*in == '&') {
2406 if (outend - out < 5) break;
2407 *out++ = '&';
2408 *out++ = 'a';
2409 *out++ = 'm';
2410 *out++ = 'p';
2411 *out++ = ';';
2412 } else if (*in == '\r') {
2413 if (outend - out < 5) break;
2414 *out++ = '&';
2415 *out++ = '#';
2416 *out++ = '1';
2417 *out++ = '3';
2418 *out++ = ';';
2419 } else {
2420 *out++ = *in;
2421 }
2422 ++in;
2423 }
2424 *outlen = out - outstart;
2425 *inlen = in - base;
2426 return(0);
2427 }
2428
2429 /**
2430 * xmlOutputBufferWriteEscape:
2431 * @out: a buffered parser output
2432 * @str: a zero terminated UTF-8 string
2433 * @escaping: an optional escaping function (or NULL)
2434 *
2435 * Write the content of the string in the output I/O buffer
2436 * This routine escapes the characters and then handle the I18N
2437 * transcoding from internal UTF-8
2438 * The buffer is lossless, i.e. will store in case of partial
2439 * or delayed writes.
2440 *
2441 * Returns the number of chars immediately written, or -1
2442 * in case of error.
2443 */
2444 int
xmlOutputBufferWriteEscape(xmlOutputBufferPtr out,const xmlChar * str,xmlCharEncodingOutputFunc escaping)2445 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
2446 xmlCharEncodingOutputFunc escaping) {
2447 int nbchars = 0; /* number of chars to output to I/O */
2448 int ret; /* return from function call */
2449 int written = 0; /* number of char written to I/O so far */
2450 int oldwritten=0;/* loop guard */
2451 int chunk; /* number of byte currently processed from str */
2452 int len; /* number of bytes in str */
2453 int cons; /* byte from str consumed */
2454
2455 if ((out == NULL) || (out->error) || (str == NULL) ||
2456 (out->buffer == NULL))
2457 return(-1);
2458 len = strlen((const char *)str);
2459 if (len < 0) return(0);
2460 if (out->error) return(-1);
2461 if (escaping == NULL) escaping = xmlEscapeContent;
2462
2463 do {
2464 oldwritten = written;
2465
2466 /*
2467 * how many bytes to consume and how many bytes to store.
2468 */
2469 cons = len;
2470 chunk = xmlBufAvail(out->buffer);
2471
2472 /*
2473 * make sure we have enough room to save first, if this is
2474 * not the case force a flush, but make sure we stay in the loop
2475 */
2476 if (chunk < 40) {
2477 if (xmlBufGrow(out->buffer, 100) < 0) {
2478 out->error = XML_ERR_NO_MEMORY;
2479 return(-1);
2480 }
2481 oldwritten = -1;
2482 continue;
2483 }
2484
2485 /*
2486 * first handle encoding stuff.
2487 */
2488 if (out->encoder != NULL) {
2489 /*
2490 * Store the data in the incoming raw buffer
2491 */
2492 if (out->conv == NULL) {
2493 out->conv = xmlBufCreate();
2494 if (out->conv == NULL) {
2495 out->error = XML_ERR_NO_MEMORY;
2496 return(-1);
2497 }
2498 }
2499 ret = escaping(xmlBufEnd(out->buffer) ,
2500 &chunk, str, &cons);
2501 if (ret < 0) {
2502 out->error = XML_ERR_NO_MEMORY;
2503 return(-1);
2504 }
2505 xmlBufAddLen(out->buffer, chunk);
2506
2507 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
2508 goto done;
2509
2510 /*
2511 * convert as much as possible to the output buffer.
2512 */
2513 ret = xmlCharEncOutput(out, 0);
2514 if (ret < 0)
2515 return(-1);
2516 if (out->writecallback)
2517 nbchars = xmlBufUse(out->conv);
2518 else
2519 nbchars = ret >= 0 ? ret : 0;
2520 } else {
2521 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
2522 if (ret < 0) {
2523 out->error = XML_ERR_NO_MEMORY;
2524 return(-1);
2525 }
2526 xmlBufAddLen(out->buffer, chunk);
2527 if (out->writecallback)
2528 nbchars = xmlBufUse(out->buffer);
2529 else
2530 nbchars = chunk;
2531 }
2532 str += cons;
2533 len -= cons;
2534
2535 if (out->writecallback) {
2536 if ((nbchars < MINLEN) && (len <= 0))
2537 goto done;
2538
2539 /*
2540 * second write the stuff to the I/O channel
2541 */
2542 if (out->encoder != NULL) {
2543 ret = out->writecallback(out->context,
2544 (const char *)xmlBufContent(out->conv), nbchars);
2545 if (ret >= 0)
2546 xmlBufShrink(out->conv, ret);
2547 } else {
2548 ret = out->writecallback(out->context,
2549 (const char *)xmlBufContent(out->buffer), nbchars);
2550 if (ret >= 0)
2551 xmlBufShrink(out->buffer, ret);
2552 }
2553 if (ret < 0) {
2554 out->error = (ret == -1) ? XML_IO_WRITE : -ret;
2555 return(-1);
2556 }
2557 if (out->written > INT_MAX - ret)
2558 out->written = INT_MAX;
2559 else
2560 out->written += ret;
2561 } else if (xmlBufAvail(out->buffer) < MINLEN) {
2562 if (xmlBufGrow(out->buffer, MINLEN) < 0) {
2563 out->error = XML_ERR_NO_MEMORY;
2564 return(-1);
2565 }
2566 }
2567 written += nbchars;
2568 } while ((len > 0) && (oldwritten != written));
2569
2570 done:
2571 return(written);
2572 }
2573
2574 /**
2575 * xmlOutputBufferWriteString:
2576 * @out: a buffered parser output
2577 * @str: a zero terminated C string
2578 *
2579 * Write the content of the string in the output I/O buffer
2580 * This routine handle the I18N transcoding from internal UTF-8
2581 * The buffer is lossless, i.e. will store in case of partial
2582 * or delayed writes.
2583 *
2584 * Returns the number of chars immediately written, or -1
2585 * in case of error.
2586 */
2587 int
xmlOutputBufferWriteString(xmlOutputBufferPtr out,const char * str)2588 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
2589 int len;
2590
2591 if ((out == NULL) || (out->error)) return(-1);
2592 if (str == NULL)
2593 return(-1);
2594 len = strlen(str);
2595
2596 if (len > 0)
2597 return(xmlOutputBufferWrite(out, len, str));
2598 return(len);
2599 }
2600
2601 /**
2602 * xmlOutputBufferWriteQuotedString:
2603 * @buf: output buffer
2604 * @string: the string to add
2605 *
2606 * routine which manage and grows an output buffer. This one writes
2607 * a quoted or double quoted #xmlChar string, checking first if it holds
2608 * quote or double-quotes internally
2609 */
2610 void
xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf,const xmlChar * string)2611 xmlOutputBufferWriteQuotedString(xmlOutputBufferPtr buf,
2612 const xmlChar *string) {
2613 const xmlChar *cur, *base;
2614
2615 if ((buf == NULL) || (buf->error))
2616 return;
2617
2618 if (xmlStrchr(string, '\"')) {
2619 if (xmlStrchr(string, '\'')) {
2620 xmlOutputBufferWrite(buf, 1, "\"");
2621 base = cur = string;
2622 while(*cur != 0){
2623 if(*cur == '"'){
2624 if (base != cur)
2625 xmlOutputBufferWrite(buf, cur - base,
2626 (const char *) base);
2627 xmlOutputBufferWrite(buf, 6, """);
2628 cur++;
2629 base = cur;
2630 }
2631 else {
2632 cur++;
2633 }
2634 }
2635 if (base != cur)
2636 xmlOutputBufferWrite(buf, cur - base, (const char *) base);
2637 xmlOutputBufferWrite(buf, 1, "\"");
2638 }
2639 else{
2640 xmlOutputBufferWrite(buf, 1, "'");
2641 xmlOutputBufferWriteString(buf, (const char *) string);
2642 xmlOutputBufferWrite(buf, 1, "'");
2643 }
2644 } else {
2645 xmlOutputBufferWrite(buf, 1, "\"");
2646 xmlOutputBufferWriteString(buf, (const char *) string);
2647 xmlOutputBufferWrite(buf, 1, "\"");
2648 }
2649 }
2650
2651 /**
2652 * xmlOutputBufferFlush:
2653 * @out: a buffered output
2654 *
2655 * flushes the output I/O channel
2656 *
2657 * Returns the number of byte written or -1 in case of error.
2658 */
2659 int
xmlOutputBufferFlush(xmlOutputBufferPtr out)2660 xmlOutputBufferFlush(xmlOutputBufferPtr out) {
2661 int nbchars = 0, ret = 0;
2662
2663 if ((out == NULL) || (out->error)) return(-1);
2664 /*
2665 * first handle encoding stuff.
2666 */
2667 if ((out->conv != NULL) && (out->encoder != NULL)) {
2668 /*
2669 * convert as much as possible to the parser output buffer.
2670 */
2671 do {
2672 nbchars = xmlCharEncOutput(out, 0);
2673 if (nbchars < 0)
2674 return(-1);
2675 } while (nbchars);
2676 }
2677
2678 /*
2679 * second flush the stuff to the I/O channel
2680 */
2681 if ((out->conv != NULL) && (out->encoder != NULL) &&
2682 (out->writecallback != NULL)) {
2683 ret = out->writecallback(out->context,
2684 (const char *)xmlBufContent(out->conv),
2685 xmlBufUse(out->conv));
2686 if (ret >= 0)
2687 xmlBufShrink(out->conv, ret);
2688 } else if (out->writecallback != NULL) {
2689 ret = out->writecallback(out->context,
2690 (const char *)xmlBufContent(out->buffer),
2691 xmlBufUse(out->buffer));
2692 if (ret >= 0)
2693 xmlBufShrink(out->buffer, ret);
2694 }
2695 if (ret < 0) {
2696 out->error = (ret == -1) ? XML_IO_WRITE : -ret;
2697 return(ret);
2698 }
2699 if (out->written > INT_MAX - ret)
2700 out->written = INT_MAX;
2701 else
2702 out->written += ret;
2703
2704 return(ret);
2705 }
2706 #endif /* LIBXML_OUTPUT_ENABLED */
2707
2708 /**
2709 * xmlParserGetDirectory:
2710 * @filename: the path to a file
2711 *
2712 * lookup the directory for that file
2713 *
2714 * Returns a new allocated string containing the directory, or NULL.
2715 */
2716 char *
xmlParserGetDirectory(const char * filename)2717 xmlParserGetDirectory(const char *filename) {
2718 char *ret = NULL;
2719 char dir[1024];
2720 char *cur;
2721
2722 if (filename == NULL) return(NULL);
2723
2724 #if defined(_WIN32)
2725 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
2726 #else
2727 # define IS_XMLPGD_SEP(ch) (ch=='/')
2728 #endif
2729
2730 strncpy(dir, filename, 1023);
2731 dir[1023] = 0;
2732 cur = &dir[strlen(dir)];
2733 while (cur > dir) {
2734 if (IS_XMLPGD_SEP(*cur)) break;
2735 cur --;
2736 }
2737 if (IS_XMLPGD_SEP(*cur)) {
2738 if (cur == dir) dir[1] = 0;
2739 else *cur = 0;
2740 ret = xmlMemStrdup(dir);
2741 } else {
2742 if (getcwd(dir, 1024) != NULL) {
2743 dir[1023] = 0;
2744 ret = xmlMemStrdup(dir);
2745 }
2746 }
2747 return(ret);
2748 #undef IS_XMLPGD_SEP
2749 }
2750
2751 /**
2752 * xmlNoNetExists:
2753 * @filename: the path to check
2754 *
2755 * DEPRECATED: Internal function, don't use.
2756 *
2757 * Like xmlCheckFilename but handles file URIs.
2758 *
2759 * Returns 0, 1, or 2.
2760 */
2761 int
xmlNoNetExists(const char * filename)2762 xmlNoNetExists(const char *filename) {
2763 char *fromUri;
2764 int ret;
2765
2766 if (filename == NULL)
2767 return(0);
2768
2769 if (xmlConvertUriToPath(filename, &fromUri) < 0)
2770 return(0);
2771
2772 if (fromUri != NULL)
2773 filename = fromUri;
2774
2775 ret = xmlCheckFilename(filename);
2776
2777 xmlFree(fromUri);
2778 return(ret);
2779 }
2780
2781 /************************************************************************
2782 * *
2783 * Input/output callbacks *
2784 * *
2785 ************************************************************************/
2786
2787 /**
2788 * xmlInitIOCallbacks:
2789 *
2790 * Initialize callback tables.
2791 */
2792 void
xmlInitIOCallbacks(void)2793 xmlInitIOCallbacks(void)
2794 {
2795 xmlInputCallbackNr = 1;
2796 xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch;
2797
2798 #ifdef LIBXML_OUTPUT_ENABLED
2799 xmlOutputCallbackNr = 1;
2800 xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch;
2801 #endif
2802 }
2803
2804 /**
2805 * xmlRegisterInputCallbacks:
2806 * @matchFunc: the xmlInputMatchCallback
2807 * @openFunc: the xmlInputOpenCallback
2808 * @readFunc: the xmlInputReadCallback
2809 * @closeFunc: the xmlInputCloseCallback
2810 *
2811 * DEPRECATED: Use xmlCtxtSetResourceLoader or similar functions.
2812 *
2813 * Register a new set of I/O callback for handling parser input.
2814 *
2815 * Returns the registered handler number or -1 in case of error
2816 */
2817 int
xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,xmlInputOpenCallback openFunc,xmlInputReadCallback readFunc,xmlInputCloseCallback closeFunc)2818 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2819 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2820 xmlInputCloseCallback closeFunc) {
2821 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2822 return(-1);
2823 }
2824 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2825 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2826 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2827 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
2828 return(xmlInputCallbackNr++);
2829 }
2830
2831 /**
2832 * xmlRegisterDefaultInputCallbacks:
2833 *
2834 * Registers the default compiled-in I/O handlers.
2835 */
2836 void
xmlRegisterDefaultInputCallbacks(void)2837 xmlRegisterDefaultInputCallbacks(void) {
2838 xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
2839 }
2840
2841 /**
2842 * xmlPopInputCallbacks:
2843 *
2844 * Clear the top input callback from the input stack. this includes the
2845 * compiled-in I/O.
2846 *
2847 * Returns the number of input callback registered or -1 in case of error.
2848 */
2849 int
xmlPopInputCallbacks(void)2850 xmlPopInputCallbacks(void)
2851 {
2852 if (xmlInputCallbackNr <= 0)
2853 return(-1);
2854
2855 xmlInputCallbackNr--;
2856
2857 return(xmlInputCallbackNr);
2858 }
2859
2860 /**
2861 * xmlCleanupInputCallbacks:
2862 *
2863 * clears the entire input callback table. this includes the
2864 * compiled-in I/O.
2865 */
2866 void
xmlCleanupInputCallbacks(void)2867 xmlCleanupInputCallbacks(void)
2868 {
2869 xmlInputCallbackNr = 0;
2870 }
2871
2872 #ifdef LIBXML_OUTPUT_ENABLED
2873 /**
2874 * xmlRegisterOutputCallbacks:
2875 * @matchFunc: the xmlOutputMatchCallback
2876 * @openFunc: the xmlOutputOpenCallback
2877 * @writeFunc: the xmlOutputWriteCallback
2878 * @closeFunc: the xmlOutputCloseCallback
2879 *
2880 * Register a new set of I/O callback for handling output.
2881 *
2882 * Returns the registered handler number or -1 in case of error
2883 */
2884 int
xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,xmlOutputOpenCallback openFunc,xmlOutputWriteCallback writeFunc,xmlOutputCloseCallback closeFunc)2885 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2886 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2887 xmlOutputCloseCallback closeFunc) {
2888 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
2889 return(-1);
2890 }
2891 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2892 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2893 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2894 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
2895 return(xmlOutputCallbackNr++);
2896 }
2897
2898 /**
2899 * xmlRegisterDefaultOutputCallbacks:
2900 *
2901 * Registers the default compiled-in I/O handlers.
2902 */
2903 void
xmlRegisterDefaultOutputCallbacks(void)2904 xmlRegisterDefaultOutputCallbacks (void) {
2905 xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
2906 }
2907
2908 /**
2909 * xmlPopOutputCallbacks:
2910 *
2911 * Remove the top output callbacks from the output stack. This includes the
2912 * compiled-in I/O.
2913 *
2914 * Returns the number of output callback registered or -1 in case of error.
2915 */
2916 int
xmlPopOutputCallbacks(void)2917 xmlPopOutputCallbacks(void)
2918 {
2919 if (xmlOutputCallbackNr <= 0)
2920 return(-1);
2921
2922 xmlOutputCallbackNr--;
2923
2924 return(xmlOutputCallbackNr);
2925 }
2926
2927 /**
2928 * xmlCleanupOutputCallbacks:
2929 *
2930 * clears the entire output callback table. this includes the
2931 * compiled-in I/O callbacks.
2932 */
2933 void
xmlCleanupOutputCallbacks(void)2934 xmlCleanupOutputCallbacks(void)
2935 {
2936 xmlOutputCallbackNr = 0;
2937 }
2938
2939 #ifdef LIBXML_HTTP_ENABLED
2940 /**
2941 * xmlRegisterHTTPPostCallbacks:
2942 *
2943 * DEPRECATED: Support for HTTP POST has been removed.
2944 */
2945 void
xmlRegisterHTTPPostCallbacks(void)2946 xmlRegisterHTTPPostCallbacks(void) {
2947 xmlRegisterDefaultOutputCallbacks();
2948 }
2949 #endif
2950 #endif /* LIBXML_OUTPUT_ENABLED */
2951
2952