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