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