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