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