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