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