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