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