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