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