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