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