blob: 855bf41ec784735f62395b31f182127da25fbc15 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
3 *
4 * See Copyright for the status of this software.
5 *
Daniel Veillard344cee72001-08-20 00:08:40 +00006 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00007 *
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
10
Daniel Veillard34ce8be2002-03-18 19:37:11 +000011#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +000012#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +000013
Owen Taylor3473f882001-02-23 17:55:21 +000014#include <string.h>
Daniel Veillard92727042002-09-17 17:59:20 +000015#ifdef HAVE_ERRNO_H
Owen Taylor3473f882001-02-23 17:55:21 +000016#include <errno.h>
Daniel Veillard92727042002-09-17 17:59:20 +000017#endif
18
Owen Taylor3473f882001-02-23 17:55:21 +000019
20#ifdef HAVE_SYS_TYPES_H
21#include <sys/types.h>
22#endif
23#ifdef HAVE_SYS_STAT_H
24#include <sys/stat.h>
25#endif
26#ifdef HAVE_FCNTL_H
27#include <fcntl.h>
28#endif
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_STDLIB_H
33#include <stdlib.h>
34#endif
35#ifdef HAVE_ZLIB_H
36#include <zlib.h>
37#endif
38
Daniel Veillard59d3ed82007-04-17 12:44:58 +000039#if defined(WIN32) || defined(_WIN32)
Daniel Veillardf7416012006-04-27 08:15:20 +000040#include <windows.h>
41#endif
42
Daniel Veillard59d3ed82007-04-17 12:44:58 +000043#if defined(_WIN32_WCE)
44#include <winnls.h> /* for CP_UTF8 */
45#endif
46
Owen Taylor3473f882001-02-23 17:55:21 +000047/* Figure a portable way to know if a file is a directory. */
48#ifndef HAVE_STAT
49# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000050 /* MS C library seems to define stat and _stat. The definition
51 is identical. Still, mapping them to each other causes a warning. */
52# ifndef _MSC_VER
53# define stat(x,y) _stat(x,y)
54# endif
Owen Taylor3473f882001-02-23 17:55:21 +000055# define HAVE_STAT
56# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000057#else
58# ifdef HAVE__STAT
Daniel Veillard0da41662006-10-10 09:05:36 +000059# if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillard8ca85b22006-09-01 09:56:07 +000060# define stat _stat
Daniel Veillard0da41662006-10-10 09:05:36 +000061# endif
Daniel Veillard8ca85b22006-09-01 09:56:07 +000062# endif
Owen Taylor3473f882001-02-23 17:55:21 +000063#endif
64#ifdef HAVE_STAT
65# ifndef S_ISDIR
66# ifdef _S_ISDIR
67# define S_ISDIR(x) _S_ISDIR(x)
68# else
69# ifdef S_IFDIR
70# ifndef S_IFMT
71# ifdef _S_IFMT
72# define S_IFMT _S_IFMT
73# endif
74# endif
75# ifdef S_IFMT
76# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
77# endif
78# endif
79# endif
80# endif
81#endif
82
83#include <libxml/xmlmemory.h>
84#include <libxml/parser.h>
85#include <libxml/parserInternals.h>
86#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000087#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000088#include <libxml/nanohttp.h>
89#include <libxml/nanoftp.h>
90#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000091#ifdef LIBXML_CATALOG_ENABLED
92#include <libxml/catalog.h>
93#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000094#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000095
Daniel Veillardf012a642001-07-23 19:10:52 +000096/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000097/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000098/* #define DEBUG_INPUT */
99
100#ifdef DEBUG_INPUT
101#define MINLEN 40
102#else
103#define MINLEN 4000
104#endif
105
106/*
107 * Input I/O callback sets
108 */
109typedef struct _xmlInputCallback {
110 xmlInputMatchCallback matchcallback;
111 xmlInputOpenCallback opencallback;
112 xmlInputReadCallback readcallback;
113 xmlInputCloseCallback closecallback;
114} xmlInputCallback;
115
116#define MAX_INPUT_CALLBACK 15
117
Daniel Veillard22090732001-07-16 00:06:07 +0000118static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
119static int xmlInputCallbackNr = 0;
120static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000121
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000122#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000123/*
124 * Output I/O callback sets
125 */
126typedef struct _xmlOutputCallback {
127 xmlOutputMatchCallback matchcallback;
128 xmlOutputOpenCallback opencallback;
129 xmlOutputWriteCallback writecallback;
130 xmlOutputCloseCallback closecallback;
131} xmlOutputCallback;
132
133#define MAX_OUTPUT_CALLBACK 15
134
Daniel Veillard22090732001-07-16 00:06:07 +0000135static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
136static int xmlOutputCallbackNr = 0;
137static int xmlOutputCallbackInitialized = 0;
Daniel Veillardda3fee42008-09-01 13:08:57 +0000138
139xmlOutputBufferPtr
140xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000141#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000142
Daniel Veillard05d987b2003-10-08 11:54:57 +0000143/************************************************************************
144 * *
145 * Tree memory error handler *
146 * *
147 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000148
Daniel Veillard05d987b2003-10-08 11:54:57 +0000149static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000150 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000151 "Permission denied", /* EACCES */
152 "Resource temporarily unavailable",/* EAGAIN */
153 "Bad file descriptor", /* EBADF */
154 "Bad message", /* EBADMSG */
155 "Resource busy", /* EBUSY */
156 "Operation canceled", /* ECANCELED */
157 "No child processes", /* ECHILD */
158 "Resource deadlock avoided",/* EDEADLK */
159 "Domain error", /* EDOM */
160 "File exists", /* EEXIST */
161 "Bad address", /* EFAULT */
162 "File too large", /* EFBIG */
163 "Operation in progress", /* EINPROGRESS */
164 "Interrupted function call",/* EINTR */
165 "Invalid argument", /* EINVAL */
166 "Input/output error", /* EIO */
167 "Is a directory", /* EISDIR */
168 "Too many open files", /* EMFILE */
169 "Too many links", /* EMLINK */
170 "Inappropriate message buffer length",/* EMSGSIZE */
171 "Filename too long", /* ENAMETOOLONG */
172 "Too many open files in system",/* ENFILE */
173 "No such device", /* ENODEV */
174 "No such file or directory",/* ENOENT */
175 "Exec format error", /* ENOEXEC */
176 "No locks available", /* ENOLCK */
177 "Not enough space", /* ENOMEM */
178 "No space left on device", /* ENOSPC */
179 "Function not implemented", /* ENOSYS */
180 "Not a directory", /* ENOTDIR */
181 "Directory not empty", /* ENOTEMPTY */
182 "Not supported", /* ENOTSUP */
183 "Inappropriate I/O control operation",/* ENOTTY */
184 "No such device or address",/* ENXIO */
185 "Operation not permitted", /* EPERM */
186 "Broken pipe", /* EPIPE */
187 "Result too large", /* ERANGE */
188 "Read-only file system", /* EROFS */
189 "Invalid seek", /* ESPIPE */
190 "No such process", /* ESRCH */
191 "Operation timed out", /* ETIMEDOUT */
192 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000193 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000194 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000195 "flush error",
196 "write error",
197 "no input",
198 "buffer full",
199 "loading error",
200 "not a socket", /* ENOTSOCK */
201 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000202 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000203 "unreachable network", /* ENETUNREACH */
204 "adddress in use", /* EADDRINUSE */
205 "already in use", /* EALREADY */
206 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000207};
208
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000209#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000210/**
211 * __xmlIOWin32UTF8ToWChar:
212 * @u8String: uft-8 string
213 *
214 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
215 */
216static wchar_t *
217__xmlIOWin32UTF8ToWChar(const char *u8String)
218{
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000219 wchar_t *wString = NULL;
Daniel Veillardf7416012006-04-27 08:15:20 +0000220
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000221 if (u8String) {
222 int wLen =
223 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
224 -1, NULL, 0);
225 if (wLen) {
226 wString = xmlMalloc(wLen * sizeof(wchar_t));
227 if (wString) {
228 if (MultiByteToWideChar
229 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
230 xmlFree(wString);
231 wString = NULL;
232 }
233 }
234 }
235 }
236
237 return wString;
Daniel Veillardf7416012006-04-27 08:15:20 +0000238}
239#endif
240
Daniel Veillard05d987b2003-10-08 11:54:57 +0000241/**
242 * xmlIOErrMemory:
243 * @extra: extra informations
244 *
245 * Handle an out of memory condition
246 */
247static void
248xmlIOErrMemory(const char *extra)
249{
250 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
251}
252
253/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000254 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000255 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000256 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000257 * @extra: extra informations
258 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000259 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000260 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000261void
262__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000263{
264 unsigned int idx;
265
266 if (code == 0) {
267#ifdef HAVE_ERRNO_H
268 if (errno == 0) code = 0;
269#ifdef EACCES
270 else if (errno == EACCES) code = XML_IO_EACCES;
271#endif
272#ifdef EAGAIN
273 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
274#endif
275#ifdef EBADF
276 else if (errno == EBADF) code = XML_IO_EBADF;
277#endif
278#ifdef EBADMSG
279 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
280#endif
281#ifdef EBUSY
282 else if (errno == EBUSY) code = XML_IO_EBUSY;
283#endif
284#ifdef ECANCELED
285 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
286#endif
287#ifdef ECHILD
288 else if (errno == ECHILD) code = XML_IO_ECHILD;
289#endif
290#ifdef EDEADLK
291 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
292#endif
293#ifdef EDOM
294 else if (errno == EDOM) code = XML_IO_EDOM;
295#endif
296#ifdef EEXIST
297 else if (errno == EEXIST) code = XML_IO_EEXIST;
298#endif
299#ifdef EFAULT
300 else if (errno == EFAULT) code = XML_IO_EFAULT;
301#endif
302#ifdef EFBIG
303 else if (errno == EFBIG) code = XML_IO_EFBIG;
304#endif
305#ifdef EINPROGRESS
306 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
307#endif
308#ifdef EINTR
309 else if (errno == EINTR) code = XML_IO_EINTR;
310#endif
311#ifdef EINVAL
312 else if (errno == EINVAL) code = XML_IO_EINVAL;
313#endif
314#ifdef EIO
315 else if (errno == EIO) code = XML_IO_EIO;
316#endif
317#ifdef EISDIR
318 else if (errno == EISDIR) code = XML_IO_EISDIR;
319#endif
320#ifdef EMFILE
321 else if (errno == EMFILE) code = XML_IO_EMFILE;
322#endif
323#ifdef EMLINK
324 else if (errno == EMLINK) code = XML_IO_EMLINK;
325#endif
326#ifdef EMSGSIZE
327 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
328#endif
329#ifdef ENAMETOOLONG
330 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
331#endif
332#ifdef ENFILE
333 else if (errno == ENFILE) code = XML_IO_ENFILE;
334#endif
335#ifdef ENODEV
336 else if (errno == ENODEV) code = XML_IO_ENODEV;
337#endif
338#ifdef ENOENT
339 else if (errno == ENOENT) code = XML_IO_ENOENT;
340#endif
341#ifdef ENOEXEC
342 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
343#endif
344#ifdef ENOLCK
345 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
346#endif
347#ifdef ENOMEM
348 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
349#endif
350#ifdef ENOSPC
351 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
352#endif
353#ifdef ENOSYS
354 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
355#endif
356#ifdef ENOTDIR
357 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
358#endif
359#ifdef ENOTEMPTY
360 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
361#endif
362#ifdef ENOTSUP
363 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
364#endif
365#ifdef ENOTTY
366 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
367#endif
368#ifdef ENXIO
369 else if (errno == ENXIO) code = XML_IO_ENXIO;
370#endif
371#ifdef EPERM
372 else if (errno == EPERM) code = XML_IO_EPERM;
373#endif
374#ifdef EPIPE
375 else if (errno == EPIPE) code = XML_IO_EPIPE;
376#endif
377#ifdef ERANGE
378 else if (errno == ERANGE) code = XML_IO_ERANGE;
379#endif
380#ifdef EROFS
381 else if (errno == EROFS) code = XML_IO_EROFS;
382#endif
383#ifdef ESPIPE
384 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
385#endif
386#ifdef ESRCH
387 else if (errno == ESRCH) code = XML_IO_ESRCH;
388#endif
389#ifdef ETIMEDOUT
390 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
391#endif
392#ifdef EXDEV
393 else if (errno == EXDEV) code = XML_IO_EXDEV;
394#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000395#ifdef ENOTSOCK
396 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
397#endif
398#ifdef EISCONN
399 else if (errno == EISCONN) code = XML_IO_EISCONN;
400#endif
401#ifdef ECONNREFUSED
402 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
403#endif
404#ifdef ETIMEDOUT
405 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
406#endif
407#ifdef ENETUNREACH
408 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
409#endif
410#ifdef EADDRINUSE
411 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
412#endif
413#ifdef EINPROGRESS
414 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
415#endif
416#ifdef EALREADY
417 else if (errno == EALREADY) code = XML_IO_EALREADY;
418#endif
419#ifdef EAFNOSUPPORT
420 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
421#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000422 else code = XML_IO_UNKNOWN;
423#endif /* HAVE_ERRNO_H */
424 }
425 idx = 0;
426 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
427 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
428
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000429 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
430}
431
432/**
433 * xmlIOErr:
434 * @code: the error number
435 * @extra: extra informations
436 *
437 * Handle an I/O error
438 */
439static void
440xmlIOErr(int code, const char *extra)
441{
442 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000443}
444
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000445/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000446 * __xmlLoaderErr:
447 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000448 * @extra: extra informations
449 *
450 * Handle a resource access error
451 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000452void
453__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000454{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000455 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000456 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000457 xmlGenericErrorFunc channel = NULL;
458 void *data = NULL;
459 xmlErrorLevel level = XML_ERR_ERROR;
460
Daniel Veillard157fee02003-10-31 10:36:03 +0000461 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
462 (ctxt->instate == XML_PARSER_EOF))
463 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000464 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
465 if (ctxt->validate) {
466 channel = ctxt->sax->error;
467 level = XML_ERR_ERROR;
468 } else {
469 channel = ctxt->sax->warning;
470 level = XML_ERR_WARNING;
471 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000472 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
473 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000474 data = ctxt->userData;
475 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000476 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000477 XML_IO_LOAD_ERROR, level, NULL, 0,
478 filename, NULL, NULL, 0, 0,
479 msg, filename);
480
481}
482
Daniel Veillard05d987b2003-10-08 11:54:57 +0000483/************************************************************************
484 * *
485 * Tree memory error handler *
486 * *
487 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000488/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000489 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000490 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000491 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000492 * This function is obsolete. Please see xmlURIFromPath in uri.c for
493 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000494 *
495 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000496 */
497xmlChar *
498xmlNormalizeWindowsPath(const xmlChar *path)
499{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000500 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000501}
502
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000503/**
504 * xmlCleanupInputCallbacks:
505 *
506 * clears the entire input callback table. this includes the
507 * compiled-in I/O.
508 */
509void
510xmlCleanupInputCallbacks(void)
511{
512 int i;
513
514 if (!xmlInputCallbackInitialized)
515 return;
516
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000517 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000518 xmlInputCallbackTable[i].matchcallback = NULL;
519 xmlInputCallbackTable[i].opencallback = NULL;
520 xmlInputCallbackTable[i].readcallback = NULL;
521 xmlInputCallbackTable[i].closecallback = NULL;
522 }
523
524 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000525 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000526}
527
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000528/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000529 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000530 *
531 * Clear the top input callback from the input stack. this includes the
532 * compiled-in I/O.
533 *
534 * Returns the number of input callback registered or -1 in case of error.
535 */
536int
537xmlPopInputCallbacks(void)
538{
539 if (!xmlInputCallbackInitialized)
540 return(-1);
541
542 if (xmlInputCallbackNr <= 0)
543 return(-1);
544
545 xmlInputCallbackNr--;
546 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
547 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
548 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
549 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
550
551 return(xmlInputCallbackNr);
552}
553
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000554#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000555/**
556 * xmlCleanupOutputCallbacks:
557 *
558 * clears the entire output callback table. this includes the
559 * compiled-in I/O callbacks.
560 */
561void
562xmlCleanupOutputCallbacks(void)
563{
564 int i;
565
566 if (!xmlOutputCallbackInitialized)
567 return;
568
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000569 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000570 xmlOutputCallbackTable[i].matchcallback = NULL;
571 xmlOutputCallbackTable[i].opencallback = NULL;
572 xmlOutputCallbackTable[i].writecallback = NULL;
573 xmlOutputCallbackTable[i].closecallback = NULL;
574 }
575
576 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000577 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000578}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000579#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000580
Owen Taylor3473f882001-02-23 17:55:21 +0000581/************************************************************************
582 * *
583 * Standard I/O for file accesses *
584 * *
585 ************************************************************************/
586
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000587#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
588
589/**
590 * xmlWrapOpenUtf8:
591 * @path: the path in utf-8 encoding
592 * @mode: type of access (0 - read, 1 - write)
593 *
594 * function opens the file specified by @path
595 *
596 */
597static FILE*
598xmlWrapOpenUtf8(const char *path,int mode)
599{
600 FILE *fd = NULL;
601 wchar_t *wPath;
602
603 wPath = __xmlIOWin32UTF8ToWChar(path);
604 if(wPath)
605 {
606 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
607 xmlFree(wPath);
608 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000609 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000610 if(fd == NULL)
611 fd = fopen(path, mode ? "wb" : "rb");
612
613 return fd;
614}
615
616/**
617 * xmlWrapStatUtf8:
618 * @path: the path in utf-8 encoding
619 * @info: structure that stores results
620 *
621 * function obtains information about the file or directory
622 *
623 */
624static int
625xmlWrapStatUtf8(const char *path,struct stat *info)
626{
627#ifdef HAVE_STAT
628 int retval = -1;
629 wchar_t *wPath;
630
631 wPath = __xmlIOWin32UTF8ToWChar(path);
632 if (wPath)
633 {
634 retval = _wstat(wPath,info);
635 xmlFree(wPath);
636 }
Daniel Veillard0da41662006-10-10 09:05:36 +0000637 /* maybe path in native encoding */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000638 if(retval < 0)
639 retval = stat(path,info);
640 return retval;
641#else
642 return -1;
643#endif
644}
645
646/**
647 * xmlWrapOpenNative:
648 * @path: the path
649 * @mode: type of access (0 - read, 1 - write)
650 *
651 * function opens the file specified by @path
652 *
653 */
654static FILE*
655xmlWrapOpenNative(const char *path,int mode)
656{
657 return fopen(path,mode ? "wb" : "rb");
658}
659
660/**
661 * xmlWrapStatNative:
662 * @path: the path
663 * @info: structure that stores results
664 *
665 * function obtains information about the file or directory
666 *
667 */
668static int
669xmlWrapStatNative(const char *path,struct stat *info)
670{
671#ifdef HAVE_STAT
672 return stat(path,info);
673#else
674 return -1;
675#endif
676}
677
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000678typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
679static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
680typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
Rob Richards6460f922006-10-12 21:08:29 +0000681static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000682
683/**
684 * xmlInitPlatformSpecificIo:
685 *
686 * Initialize platform specific features.
687 */
688static void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +0000689xmlInitPlatformSpecificIo(void)
690{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000691 static int xmlPlatformIoInitialized = 0;
692 OSVERSIONINFO osvi;
693
694 if(xmlPlatformIoInitialized)
695 return;
696
697 osvi.dwOSVersionInfoSize = sizeof(osvi);
698
699 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
700 xmlWrapStat = xmlWrapStatUtf8;
701 xmlWrapOpen = xmlWrapOpenUtf8;
702 } else {
703 xmlWrapStat = xmlWrapStatNative;
704 xmlWrapOpen = xmlWrapOpenNative;
705 }
706
707 xmlPlatformIoInitialized = 1;
708 return;
709}
710
711#endif
712
Owen Taylor3473f882001-02-23 17:55:21 +0000713/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000714 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000715 * @path: the path to check
716 *
717 * function checks to see if @path is a valid source
718 * (file, socket...) for XML.
719 *
720 * if stat is not available on the target machine,
721 * returns 1. if stat fails, returns 0 (if calling
722 * stat on the filename fails, it can't be right).
723 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000724 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000725 */
726
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000727int
Owen Taylor3473f882001-02-23 17:55:21 +0000728xmlCheckFilename (const char *path)
729{
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000730#ifdef HAVE_STAT
Daniel Veillard0b309952006-05-02 20:34:38 +0000731 struct stat stat_buffer;
732#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000733 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000734 return(0);
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000735
Owen Taylor3473f882001-02-23 17:55:21 +0000736#ifdef HAVE_STAT
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000737#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
738 if (xmlWrapStat(path, &stat_buffer) == -1)
739 return 0;
740#else
Owen Taylor3473f882001-02-23 17:55:21 +0000741 if (stat(path, &stat_buffer) == -1)
742 return 0;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000743#endif
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000744#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000745 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000746 return 2;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000747#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000748#endif /* HAVE_STAT */
Owen Taylor3473f882001-02-23 17:55:21 +0000749 return 1;
750}
751
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000752static int
Owen Taylor3473f882001-02-23 17:55:21 +0000753xmlNop(void) {
754 return(0);
755}
756
757/**
Owen Taylor3473f882001-02-23 17:55:21 +0000758 * xmlFdRead:
759 * @context: the I/O context
760 * @buffer: where to drop data
761 * @len: number of bytes to read
762 *
763 * Read @len bytes to @buffer from the I/O channel.
764 *
765 * Returns the number of bytes written
766 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000767static int
Owen Taylor3473f882001-02-23 17:55:21 +0000768xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000769 int ret;
770
771 ret = read((int) (long) context, &buffer[0], len);
772 if (ret < 0) xmlIOErr(0, "read()");
773 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000774}
775
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000776#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000777/**
778 * xmlFdWrite:
779 * @context: the I/O context
780 * @buffer: where to get data
781 * @len: number of bytes to write
782 *
783 * Write @len bytes from @buffer to the I/O channel.
784 *
785 * Returns the number of bytes written
786 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000787static int
Owen Taylor3473f882001-02-23 17:55:21 +0000788xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000789 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000790
Daniel Veillard9b693b42005-10-28 14:54:17 +0000791 if (len > 0) {
792 ret = write((int) (long) context, &buffer[0], len);
793 if (ret < 0) xmlIOErr(0, "write()");
794 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000795 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000796}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000797#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000798
799/**
800 * xmlFdClose:
801 * @context: the I/O context
802 *
803 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000804 *
805 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000806 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000807static int
Owen Taylor3473f882001-02-23 17:55:21 +0000808xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000809 int ret;
810 ret = close((int) (long) context);
811 if (ret < 0) xmlIOErr(0, "close()");
812 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000813}
814
815/**
816 * xmlFileMatch:
817 * @filename: the URI for matching
818 *
819 * input from FILE *
820 *
821 * Returns 1 if matches, 0 otherwise
822 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000823int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000824xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000825 return(1);
826}
827
828/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000829 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000830 * @filename: the URI for matching
831 *
832 * input from FILE *, supports compressed input
833 * if @filename is " " then the standard input is used
834 *
835 * Returns an I/O context or NULL in case of error
836 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000837static void *
838xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000839 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000840 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000841
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000842 if (filename == NULL)
843 return(NULL);
844
Owen Taylor3473f882001-02-23 17:55:21 +0000845 if (!strcmp(filename, "-")) {
846 fd = stdin;
847 return((void *) fd);
848 }
849
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000850 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000851#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000852 path = &filename[17];
853#else
Owen Taylor3473f882001-02-23 17:55:21 +0000854 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000855#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000856 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000857#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000858 path = &filename[8];
859#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000860 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000861#endif
Daniel Veillard5cdbbd22007-06-12 09:39:14 +0000862 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
863 /* lots of generators seems to lazy to read RFC 1738 */
864#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
865 path = &filename[6];
866#else
867 path = &filename[5];
868#endif
Daniel Veillardfe703322001-08-14 12:18:09 +0000869 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000870 path = filename;
871
872 if (path == NULL)
873 return(NULL);
874 if (!xmlCheckFilename(path))
875 return(NULL);
876
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000877#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
878 fd = xmlWrapOpen(path, 0);
879#else
880 fd = fopen(path, "r");
Owen Taylor3473f882001-02-23 17:55:21 +0000881#endif /* WIN32 */
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000882 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000883 return((void *) fd);
884}
885
886/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000887 * xmlFileOpen:
888 * @filename: the URI for matching
889 *
890 * Wrapper around xmlFileOpen_real that try it with an unescaped
891 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000892 *
893 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000894 */
895void *
896xmlFileOpen (const char *filename) {
897 char *unescaped;
898 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000899
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000900 retval = xmlFileOpen_real(filename);
901 if (retval == NULL) {
902 unescaped = xmlURIUnescapeString(filename, 0, NULL);
903 if (unescaped != NULL) {
904 retval = xmlFileOpen_real(unescaped);
905 xmlFree(unescaped);
906 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000907 }
Daniel Veillardbd672bc2007-03-30 12:39:25 +0000908
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000909 return retval;
910}
911
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000912#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000913/**
Owen Taylor3473f882001-02-23 17:55:21 +0000914 * xmlFileOpenW:
915 * @filename: the URI for matching
916 *
917 * output to from FILE *,
918 * if @filename is "-" then the standard output is used
919 *
920 * Returns an I/O context or NULL in case of error
921 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000922static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000923xmlFileOpenW (const char *filename) {
924 const char *path = NULL;
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000925 FILE *fd;
Owen Taylor3473f882001-02-23 17:55:21 +0000926
927 if (!strcmp(filename, "-")) {
928 fd = stdout;
929 return((void *) fd);
930 }
931
Daniel Veillardf4862f02002-09-10 11:13:43 +0000932 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000933#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000934 path = &filename[17];
935#else
Owen Taylor3473f882001-02-23 17:55:21 +0000936 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000937#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000938 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000939#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000940 path = &filename[8];
941#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000942 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000943#endif
944 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000945 path = filename;
946
947 if (path == NULL)
948 return(NULL);
949
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000950#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
951 fd = xmlWrapOpen(path, 1);
952#else
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000953 fd = fopen(path, "wb");
Daniel Veillard8ca85b22006-09-01 09:56:07 +0000954#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000955
Daniel Veillardf7416012006-04-27 08:15:20 +0000956 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000957 return((void *) fd);
958}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000959#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000960
961/**
962 * xmlFileRead:
963 * @context: the I/O context
964 * @buffer: where to drop data
965 * @len: number of bytes to write
966 *
967 * Read @len bytes to @buffer from the I/O channel.
968 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000969 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000970 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000971int
Owen Taylor3473f882001-02-23 17:55:21 +0000972xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000973 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000974 if ((context == NULL) || (buffer == NULL))
975 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000976 ret = fread(&buffer[0], 1, len, (FILE *) context);
977 if (ret < 0) xmlIOErr(0, "fread()");
978 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000979}
980
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000981#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000982/**
983 * xmlFileWrite:
984 * @context: the I/O context
985 * @buffer: where to drop data
986 * @len: number of bytes to write
987 *
988 * Write @len bytes from @buffer to the I/O channel.
989 *
990 * Returns the number of bytes written
991 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000992static int
Owen Taylor3473f882001-02-23 17:55:21 +0000993xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000994 int items;
995
Daniel Veillardce682bc2004-11-05 17:22:25 +0000996 if ((context == NULL) || (buffer == NULL))
997 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000998 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +0000999 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001000 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001001 return(-1);
1002 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001003 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001004}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001005#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001006
1007/**
1008 * xmlFileClose:
1009 * @context: the I/O context
1010 *
1011 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001012 *
1013 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001014 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001015int
Owen Taylor3473f882001-02-23 17:55:21 +00001016xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001017 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001018 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001019
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001020 if (context == NULL)
1021 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001022 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001023 if ((fil == stdout) || (fil == stderr)) {
1024 ret = fflush(fil);
1025 if (ret < 0)
1026 xmlIOErr(0, "fflush()");
1027 return(0);
1028 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001029 if (fil == stdin)
1030 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001031 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1032 if (ret < 0)
1033 xmlIOErr(0, "fclose()");
1034 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001035}
1036
1037/**
1038 * xmlFileFlush:
1039 * @context: the I/O context
1040 *
1041 * Flush an I/O channel
1042 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001043static int
Owen Taylor3473f882001-02-23 17:55:21 +00001044xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001045 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001046
1047 if (context == NULL)
1048 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001049 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1050 if (ret < 0)
1051 xmlIOErr(0, "fflush()");
1052 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001053}
1054
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001055#ifdef LIBXML_OUTPUT_ENABLED
1056/**
1057 * xmlBufferWrite:
1058 * @context: the xmlBuffer
1059 * @buffer: the data to write
1060 * @len: number of bytes to write
1061 *
1062 * Write @len bytes from @buffer to the xml buffer
1063 *
1064 * Returns the number of bytes written
1065 */
1066static int
1067xmlBufferWrite (void * context, const char * buffer, int len) {
1068 int ret;
1069
1070 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1071 if (ret != 0)
1072 return(-1);
1073 return(len);
1074}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001075#endif
1076
Owen Taylor3473f882001-02-23 17:55:21 +00001077#ifdef HAVE_ZLIB_H
1078/************************************************************************
1079 * *
1080 * I/O for compressed file accesses *
1081 * *
1082 ************************************************************************/
1083/**
1084 * xmlGzfileMatch:
1085 * @filename: the URI for matching
1086 *
1087 * input from compressed file test
1088 *
1089 * Returns 1 if matches, 0 otherwise
1090 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001091static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001092xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001093 return(1);
1094}
1095
1096/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001097 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001098 * @filename: the URI for matching
1099 *
1100 * input from compressed file open
1101 * if @filename is " " then the standard input is used
1102 *
1103 * Returns an I/O context or NULL in case of error
1104 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001105static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001106xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001107 const char *path = NULL;
1108 gzFile fd;
1109
1110 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001111 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001112 return((void *) fd);
1113 }
1114
Daniel Veillardf4862f02002-09-10 11:13:43 +00001115 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001116#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001117 path = &filename[17];
1118#else
Owen Taylor3473f882001-02-23 17:55:21 +00001119 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001120#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001121 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001122#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001123 path = &filename[8];
1124#else
Owen Taylor3473f882001-02-23 17:55:21 +00001125 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001126#endif
1127 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001128 path = filename;
1129
1130 if (path == NULL)
1131 return(NULL);
1132 if (!xmlCheckFilename(path))
1133 return(NULL);
1134
1135 fd = gzopen(path, "rb");
1136 return((void *) fd);
1137}
1138
1139/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001140 * xmlGzfileOpen:
1141 * @filename: the URI for matching
1142 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001143 * Wrapper around xmlGzfileOpen if the open fais, it will
1144 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001145 */
1146static void *
1147xmlGzfileOpen (const char *filename) {
1148 char *unescaped;
1149 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001150
1151 retval = xmlGzfileOpen_real(filename);
1152 if (retval == NULL) {
1153 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1154 if (unescaped != NULL) {
1155 retval = xmlGzfileOpen_real(unescaped);
1156 }
1157 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001158 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001159 return retval;
1160}
1161
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001162#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001163/**
Owen Taylor3473f882001-02-23 17:55:21 +00001164 * xmlGzfileOpenW:
1165 * @filename: the URI for matching
1166 * @compression: the compression factor (0 - 9 included)
1167 *
1168 * input from compressed file open
1169 * if @filename is " " then the standard input is used
1170 *
1171 * Returns an I/O context or NULL in case of error
1172 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001173static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001174xmlGzfileOpenW (const char *filename, int compression) {
1175 const char *path = NULL;
1176 char mode[15];
1177 gzFile fd;
1178
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001179 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001180 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001181 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001182 return((void *) fd);
1183 }
1184
Daniel Veillardf4862f02002-09-10 11:13:43 +00001185 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001186#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001187 path = &filename[17];
1188#else
Owen Taylor3473f882001-02-23 17:55:21 +00001189 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001190#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001191 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001192#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001193 path = &filename[8];
1194#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001195 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001196#endif
1197 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001198 path = filename;
1199
1200 if (path == NULL)
1201 return(NULL);
1202
1203 fd = gzopen(path, mode);
1204 return((void *) fd);
1205}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001206#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001207
1208/**
1209 * xmlGzfileRead:
1210 * @context: the I/O context
1211 * @buffer: where to drop data
1212 * @len: number of bytes to write
1213 *
1214 * Read @len bytes to @buffer from the compressed I/O channel.
1215 *
1216 * Returns the number of bytes written
1217 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001218static int
Owen Taylor3473f882001-02-23 17:55:21 +00001219xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001220 int ret;
1221
1222 ret = gzread((gzFile) context, &buffer[0], len);
1223 if (ret < 0) xmlIOErr(0, "gzread()");
1224 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001225}
1226
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001227#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001228/**
1229 * xmlGzfileWrite:
1230 * @context: the I/O context
1231 * @buffer: where to drop data
1232 * @len: number of bytes to write
1233 *
1234 * Write @len bytes from @buffer to the compressed I/O channel.
1235 *
1236 * Returns the number of bytes written
1237 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001238static int
Owen Taylor3473f882001-02-23 17:55:21 +00001239xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001240 int ret;
1241
1242 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1243 if (ret < 0) xmlIOErr(0, "gzwrite()");
1244 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001245}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001246#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001247
1248/**
1249 * xmlGzfileClose:
1250 * @context: the I/O context
1251 *
1252 * Close a compressed I/O channel
1253 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001254static int
Owen Taylor3473f882001-02-23 17:55:21 +00001255xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001256 int ret;
1257
1258 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1259 if (ret < 0) xmlIOErr(0, "gzclose()");
1260 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001261}
1262#endif /* HAVE_ZLIB_H */
1263
1264#ifdef LIBXML_HTTP_ENABLED
1265/************************************************************************
1266 * *
1267 * I/O for HTTP file accesses *
1268 * *
1269 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001270
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001271#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001272typedef struct xmlIOHTTPWriteCtxt_
1273{
1274 int compression;
1275
1276 char * uri;
1277
1278 void * doc_buff;
1279
1280} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1281
1282#ifdef HAVE_ZLIB_H
1283
1284#define DFLT_WBITS ( -15 )
1285#define DFLT_MEM_LVL ( 8 )
1286#define GZ_MAGIC1 ( 0x1f )
1287#define GZ_MAGIC2 ( 0x8b )
1288#define LXML_ZLIB_OS_CODE ( 0x03 )
1289#define INIT_HTTP_BUFF_SIZE ( 32768 )
1290#define DFLT_ZLIB_RATIO ( 5 )
1291
1292/*
1293** Data structure and functions to work with sending compressed data
1294** via HTTP.
1295*/
1296
1297typedef struct xmlZMemBuff_
1298{
1299 unsigned long size;
1300 unsigned long crc;
1301
1302 unsigned char * zbuff;
1303 z_stream zctrl;
1304
1305} xmlZMemBuff, *xmlZMemBuffPtr;
1306
1307/**
1308 * append_reverse_ulong
1309 * @buff: Compressed memory buffer
1310 * @data: Unsigned long to append
1311 *
1312 * Append a unsigned long in reverse byte order to the end of the
1313 * memory buffer.
1314 */
1315static void
1316append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1317
1318 int idx;
1319
1320 if ( buff == NULL )
1321 return;
1322
1323 /*
1324 ** This is plagiarized from putLong in gzio.c (zlib source) where
1325 ** the number "4" is hardcoded. If zlib is ever patched to
1326 ** support 64 bit file sizes, this code would need to be patched
1327 ** as well.
1328 */
1329
1330 for ( idx = 0; idx < 4; idx++ ) {
1331 *buff->zctrl.next_out = ( data & 0xff );
1332 data >>= 8;
1333 buff->zctrl.next_out++;
1334 }
1335
1336 return;
1337}
1338
1339/**
1340 *
1341 * xmlFreeZMemBuff
1342 * @buff: The memory buffer context to clear
1343 *
1344 * Release all the resources associated with the compressed memory buffer.
1345 */
1346static void
1347xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001348
1349#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001350 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001351#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001352
1353 if ( buff == NULL )
1354 return;
1355
1356 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001357#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001358 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001359 if ( z_err != Z_OK )
1360 xmlGenericError( xmlGenericErrorContext,
1361 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1362 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001363#else
1364 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001365#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001366
1367 xmlFree( buff );
1368 return;
1369}
1370
1371/**
1372 * xmlCreateZMemBuff
1373 *@compression: Compression value to use
1374 *
1375 * Create a memory buffer to hold the compressed XML document. The
1376 * compressed document in memory will end up being identical to what
1377 * would be created if gzopen/gzwrite/gzclose were being used to
1378 * write the document to disk. The code for the header/trailer data to
1379 * the compression is plagiarized from the zlib source files.
1380 */
1381static void *
1382xmlCreateZMemBuff( int compression ) {
1383
1384 int z_err;
1385 int hdr_lgth;
1386 xmlZMemBuffPtr buff = NULL;
1387
1388 if ( ( compression < 1 ) || ( compression > 9 ) )
1389 return ( NULL );
1390
1391 /* Create the control and data areas */
1392
1393 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1394 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001395 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001396 return ( NULL );
1397 }
1398
1399 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1400 buff->size = INIT_HTTP_BUFF_SIZE;
1401 buff->zbuff = xmlMalloc( buff->size );
1402 if ( buff->zbuff == NULL ) {
1403 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001404 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001405 return ( NULL );
1406 }
1407
1408 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1409 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1410 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001411 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001412 xmlFreeZMemBuff( buff );
1413 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001414 xmlStrPrintf(msg, 500,
1415 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1416 "Error initializing compression context. ZLIB error:",
1417 z_err );
1418 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001419 return ( NULL );
1420 }
1421
1422 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001423 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001424 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1425 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001426 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1427 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1428 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1429 buff->zctrl.avail_out = buff->size - hdr_lgth;
1430
1431 return ( buff );
1432}
1433
1434/**
1435 * xmlZMemBuffExtend
1436 * @buff: Buffer used to compress and consolidate data.
1437 * @ext_amt: Number of bytes to extend the buffer.
1438 *
1439 * Extend the internal buffer used to store the compressed data by the
1440 * specified amount.
1441 *
1442 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1443 * the original buffer still exists at the original size.
1444 */
1445static int
1446xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1447
1448 int rc = -1;
1449 size_t new_size;
1450 size_t cur_used;
1451
1452 unsigned char * tmp_ptr = NULL;
1453
1454 if ( buff == NULL )
1455 return ( -1 );
1456
1457 else if ( ext_amt == 0 )
1458 return ( 0 );
1459
1460 cur_used = buff->zctrl.next_out - buff->zbuff;
1461 new_size = buff->size + ext_amt;
1462
1463#ifdef DEBUG_HTTP
1464 if ( cur_used > new_size )
1465 xmlGenericError( xmlGenericErrorContext,
1466 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1467 "Buffer overwrite detected during compressed memory",
1468 "buffer extension. Overflowed by",
1469 (cur_used - new_size ) );
1470#endif
1471
1472 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1473 if ( tmp_ptr != NULL ) {
1474 rc = 0;
1475 buff->size = new_size;
1476 buff->zbuff = tmp_ptr;
1477 buff->zctrl.next_out = tmp_ptr + cur_used;
1478 buff->zctrl.avail_out = new_size - cur_used;
1479 }
1480 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001481 xmlChar msg[500];
1482 xmlStrPrintf(msg, 500,
1483 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1484 "Allocation failure extending output buffer to",
1485 new_size );
1486 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001487 }
1488
1489 return ( rc );
1490}
1491
1492/**
1493 * xmlZMemBuffAppend
1494 * @buff: Buffer used to compress and consolidate data
1495 * @src: Uncompressed source content to append to buffer
1496 * @len: Length of source data to append to buffer
1497 *
1498 * Compress and append data to the internal buffer. The data buffer
1499 * will be expanded if needed to store the additional data.
1500 *
1501 * Returns the number of bytes appended to the buffer or -1 on error.
1502 */
1503static int
1504xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1505
1506 int z_err;
1507 size_t min_accept;
1508
1509 if ( ( buff == NULL ) || ( src == NULL ) )
1510 return ( -1 );
1511
1512 buff->zctrl.avail_in = len;
1513 buff->zctrl.next_in = (unsigned char *)src;
1514 while ( buff->zctrl.avail_in > 0 ) {
1515 /*
1516 ** Extend the buffer prior to deflate call if a reasonable amount
1517 ** of output buffer space is not available.
1518 */
1519 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1520 if ( buff->zctrl.avail_out <= min_accept ) {
1521 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1522 return ( -1 );
1523 }
1524
1525 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1526 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001527 xmlChar msg[500];
1528 xmlStrPrintf(msg, 500,
1529 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001530 "Compression error while appending",
1531 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001532 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001533 return ( -1 );
1534 }
1535 }
1536
1537 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1538
1539 return ( len );
1540}
1541
1542/**
1543 * xmlZMemBuffGetContent
1544 * @buff: Compressed memory content buffer
1545 * @data_ref: Pointer reference to point to compressed content
1546 *
1547 * Flushes the compression buffers, appends gzip file trailers and
1548 * returns the compressed content and length of the compressed data.
1549 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1550 *
1551 * Returns the length of the compressed data or -1 on error.
1552 */
1553static int
1554xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1555
1556 int zlgth = -1;
1557 int z_err;
1558
1559 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1560 return ( -1 );
1561
1562 /* Need to loop until compression output buffers are flushed */
1563
1564 do
1565 {
1566 z_err = deflate( &buff->zctrl, Z_FINISH );
1567 if ( z_err == Z_OK ) {
1568 /* In this case Z_OK means more buffer space needed */
1569
1570 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1571 return ( -1 );
1572 }
1573 }
1574 while ( z_err == Z_OK );
1575
1576 /* If the compression state is not Z_STREAM_END, some error occurred */
1577
1578 if ( z_err == Z_STREAM_END ) {
1579
1580 /* Need to append the gzip data trailer */
1581
1582 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1583 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1584 return ( -1 );
1585 }
1586
1587 /*
1588 ** For whatever reason, the CRC and length data are pushed out
1589 ** in reverse byte order. So a memcpy can't be used here.
1590 */
1591
1592 append_reverse_ulong( buff, buff->crc );
1593 append_reverse_ulong( buff, buff->zctrl.total_in );
1594
1595 zlgth = buff->zctrl.next_out - buff->zbuff;
1596 *data_ref = (char *)buff->zbuff;
1597 }
1598
Daniel Veillard05d987b2003-10-08 11:54:57 +00001599 else {
1600 xmlChar msg[500];
1601 xmlStrPrintf(msg, 500,
1602 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1603 "Error flushing zlib buffers. Error code", z_err );
1604 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1605 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001606
1607 return ( zlgth );
1608}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001609#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001610#endif /* HAVE_ZLIB_H */
1611
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001612#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001613/**
1614 * xmlFreeHTTPWriteCtxt
1615 * @ctxt: Context to cleanup
1616 *
1617 * Free allocated memory and reclaim system resources.
1618 *
1619 * No return value.
1620 */
1621static void
1622xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1623{
1624 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001625 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001626
1627 if ( ctxt->doc_buff != NULL ) {
1628
1629#ifdef HAVE_ZLIB_H
1630 if ( ctxt->compression > 0 ) {
1631 xmlFreeZMemBuff( ctxt->doc_buff );
1632 }
1633 else
1634#endif
1635 {
1636 xmlOutputBufferClose( ctxt->doc_buff );
1637 }
1638 }
1639
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001640 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001641 return;
1642}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001643#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001644
1645
Owen Taylor3473f882001-02-23 17:55:21 +00001646/**
1647 * xmlIOHTTPMatch:
1648 * @filename: the URI for matching
1649 *
1650 * check if the URI matches an HTTP one
1651 *
1652 * Returns 1 if matches, 0 otherwise
1653 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001654int
Owen Taylor3473f882001-02-23 17:55:21 +00001655xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001656 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001657 return(1);
1658 return(0);
1659}
1660
1661/**
1662 * xmlIOHTTPOpen:
1663 * @filename: the URI for matching
1664 *
1665 * open an HTTP I/O channel
1666 *
1667 * Returns an I/O context or NULL in case of error
1668 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001669void *
Owen Taylor3473f882001-02-23 17:55:21 +00001670xmlIOHTTPOpen (const char *filename) {
1671 return(xmlNanoHTTPOpen(filename, NULL));
1672}
1673
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001674#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001675/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001676 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001677 * @post_uri: The destination URI for the document
1678 * @compression: The compression desired for the document.
1679 *
1680 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1681 * request. Non-static as is called from the output buffer creation routine.
1682 *
1683 * Returns an I/O context or NULL in case of error.
1684 */
1685
1686void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001687xmlIOHTTPOpenW(const char *post_uri, int compression)
1688{
Daniel Veillardf012a642001-07-23 19:10:52 +00001689
Daniel Veillard572577e2002-01-18 16:23:55 +00001690 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001691
Daniel Veillard572577e2002-01-18 16:23:55 +00001692 if (post_uri == NULL)
1693 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001694
Daniel Veillard572577e2002-01-18 16:23:55 +00001695 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1696 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001697 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001698 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001699 }
1700
Daniel Veillard572577e2002-01-18 16:23:55 +00001701 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001702
Daniel Veillard572577e2002-01-18 16:23:55 +00001703 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1704 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001705 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001706 xmlFreeHTTPWriteCtxt(ctxt);
1707 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001708 }
1709
1710 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001711 * ** Since the document length is required for an HTTP post,
1712 * ** need to put the document into a buffer. A memory buffer
1713 * ** is being used to avoid pushing the data to disk and back.
1714 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001715
1716#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001717 if ((compression > 0) && (compression <= 9)) {
1718
1719 ctxt->compression = compression;
1720 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1721 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001722#endif
1723 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001724 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001725
Daniel Veillardda3fee42008-09-01 13:08:57 +00001726 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001727 }
1728
Daniel Veillard572577e2002-01-18 16:23:55 +00001729 if (ctxt->doc_buff == NULL) {
1730 xmlFreeHTTPWriteCtxt(ctxt);
1731 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001732 }
1733
Daniel Veillard572577e2002-01-18 16:23:55 +00001734 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001735}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001736#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardda3fee42008-09-01 13:08:57 +00001737
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001738#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001739/**
1740 * xmlIOHTTPDfltOpenW
1741 * @post_uri: The destination URI for this document.
1742 *
1743 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1744 * HTTP post command. This function should generally not be used as
1745 * the open callback is short circuited in xmlOutputBufferCreateFile.
1746 *
1747 * Returns a pointer to the new IO context.
1748 */
1749static void *
1750xmlIOHTTPDfltOpenW( const char * post_uri ) {
1751 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1752}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001753#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001754
1755/**
Owen Taylor3473f882001-02-23 17:55:21 +00001756 * xmlIOHTTPRead:
1757 * @context: the I/O context
1758 * @buffer: where to drop data
1759 * @len: number of bytes to write
1760 *
1761 * Read @len bytes to @buffer from the I/O channel.
1762 *
1763 * Returns the number of bytes written
1764 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001765int
Owen Taylor3473f882001-02-23 17:55:21 +00001766xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001767 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001768 return(xmlNanoHTTPRead(context, &buffer[0], len));
1769}
1770
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001771#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001772/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001773 * xmlIOHTTPWrite
1774 * @context: previously opened writing context
1775 * @buffer: data to output to temporary buffer
1776 * @len: bytes to output
1777 *
1778 * Collect data from memory buffer into a temporary file for later
1779 * processing.
1780 *
1781 * Returns number of bytes written.
1782 */
1783
1784static int
1785xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1786
1787 xmlIOHTTPWriteCtxtPtr ctxt = context;
1788
1789 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1790 return ( -1 );
1791
1792 if ( len > 0 ) {
1793
1794 /* Use gzwrite or fwrite as previously setup in the open call */
1795
1796#ifdef HAVE_ZLIB_H
1797 if ( ctxt->compression > 0 )
1798 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1799
1800 else
1801#endif
1802 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1803
1804 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001805 xmlChar msg[500];
1806 xmlStrPrintf(msg, 500,
1807 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001808 "Error appending to internal buffer.",
1809 "Error sending document to URI",
1810 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001811 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001812 }
1813 }
1814
1815 return ( len );
1816}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001817#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001818
1819
1820/**
Owen Taylor3473f882001-02-23 17:55:21 +00001821 * xmlIOHTTPClose:
1822 * @context: the I/O context
1823 *
1824 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001825 *
1826 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001827 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001828int
Owen Taylor3473f882001-02-23 17:55:21 +00001829xmlIOHTTPClose (void * context) {
1830 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001831 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001832}
Daniel Veillardf012a642001-07-23 19:10:52 +00001833
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001834#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001835/**
1836 * xmlIOHTTCloseWrite
1837 * @context: The I/O context
1838 * @http_mthd: The HTTP method to be used when sending the data
1839 *
1840 * Close the transmit HTTP I/O channel and actually send the data.
1841 */
1842static int
1843xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1844
1845 int close_rc = -1;
1846 int http_rtn = 0;
1847 int content_lgth = 0;
1848 xmlIOHTTPWriteCtxtPtr ctxt = context;
1849
1850 char * http_content = NULL;
1851 char * content_encoding = NULL;
1852 char * content_type = (char *) "text/xml";
1853 void * http_ctxt = NULL;
1854
1855 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1856 return ( -1 );
1857
1858 /* Retrieve the content from the appropriate buffer */
1859
1860#ifdef HAVE_ZLIB_H
1861
1862 if ( ctxt->compression > 0 ) {
1863 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1864 content_encoding = (char *) "Content-Encoding: gzip";
1865 }
1866 else
1867#endif
1868 {
1869 /* Pull the data out of the memory output buffer */
1870
1871 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1872 http_content = (char *)dctxt->buffer->content;
1873 content_lgth = dctxt->buffer->use;
1874 }
1875
1876 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001877 xmlChar msg[500];
1878 xmlStrPrintf(msg, 500,
1879 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1880 "Error retrieving content.\nUnable to",
1881 http_mthd, "data to URI", ctxt->uri );
1882 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001883 }
1884
1885 else {
1886
1887 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1888 &content_type, content_encoding,
1889 content_lgth );
1890
1891 if ( http_ctxt != NULL ) {
1892#ifdef DEBUG_HTTP
1893 /* If testing/debugging - dump reply with request content */
1894
1895 FILE * tst_file = NULL;
1896 char buffer[ 4096 ];
1897 char * dump_name = NULL;
1898 int avail;
1899
1900 xmlGenericError( xmlGenericErrorContext,
1901 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1902 http_mthd, ctxt->uri,
1903 xmlNanoHTTPReturnCode( http_ctxt ) );
1904
1905 /*
1906 ** Since either content or reply may be gzipped,
1907 ** dump them to separate files instead of the
1908 ** standard error context.
1909 */
1910
1911 dump_name = tempnam( NULL, "lxml" );
1912 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001913 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001914
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001915 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001916 if ( tst_file != NULL ) {
1917 xmlGenericError( xmlGenericErrorContext,
1918 "Transmitted content saved in file: %s\n", buffer );
1919
1920 fwrite( http_content, sizeof( char ),
1921 content_lgth, tst_file );
1922 fclose( tst_file );
1923 }
1924
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001925 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001926 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001927 if ( tst_file != NULL ) {
1928 xmlGenericError( xmlGenericErrorContext,
1929 "Reply content saved in file: %s\n", buffer );
1930
1931
1932 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1933 buffer, sizeof( buffer ) )) > 0 ) {
1934
1935 fwrite( buffer, sizeof( char ), avail, tst_file );
1936 }
1937
1938 fclose( tst_file );
1939 }
1940
1941 free( dump_name );
1942 }
1943#endif /* DEBUG_HTTP */
1944
1945 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1946 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1947 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001948 else {
1949 xmlChar msg[500];
1950 xmlStrPrintf(msg, 500,
1951 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001952 http_mthd, content_lgth,
1953 "bytes to URI", ctxt->uri,
1954 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001955 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1956 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001957
1958 xmlNanoHTTPClose( http_ctxt );
1959 xmlFree( content_type );
1960 }
1961 }
1962
1963 /* Final cleanups */
1964
1965 xmlFreeHTTPWriteCtxt( ctxt );
1966
1967 return ( close_rc );
1968}
1969
1970/**
1971 * xmlIOHTTPClosePut
1972 *
1973 * @context: The I/O context
1974 *
1975 * Close the transmit HTTP I/O channel and actually send data using a PUT
1976 * HTTP method.
1977 */
1978static int
1979xmlIOHTTPClosePut( void * ctxt ) {
1980 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1981}
1982
1983
1984/**
1985 * xmlIOHTTPClosePost
1986 *
1987 * @context: The I/O context
1988 *
1989 * Close the transmit HTTP I/O channel and actually send data using a POST
1990 * HTTP method.
1991 */
1992static int
1993xmlIOHTTPClosePost( void * ctxt ) {
1994 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1995}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001996#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001997
Owen Taylor3473f882001-02-23 17:55:21 +00001998#endif /* LIBXML_HTTP_ENABLED */
1999
2000#ifdef LIBXML_FTP_ENABLED
2001/************************************************************************
2002 * *
2003 * I/O for FTP file accesses *
2004 * *
2005 ************************************************************************/
2006/**
2007 * xmlIOFTPMatch:
2008 * @filename: the URI for matching
2009 *
2010 * check if the URI matches an FTP one
2011 *
2012 * Returns 1 if matches, 0 otherwise
2013 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002014int
Owen Taylor3473f882001-02-23 17:55:21 +00002015xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002016 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002017 return(1);
2018 return(0);
2019}
2020
2021/**
2022 * xmlIOFTPOpen:
2023 * @filename: the URI for matching
2024 *
2025 * open an FTP I/O channel
2026 *
2027 * Returns an I/O context or NULL in case of error
2028 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002029void *
Owen Taylor3473f882001-02-23 17:55:21 +00002030xmlIOFTPOpen (const char *filename) {
2031 return(xmlNanoFTPOpen(filename));
2032}
2033
2034/**
2035 * xmlIOFTPRead:
2036 * @context: the I/O context
2037 * @buffer: where to drop data
2038 * @len: number of bytes to write
2039 *
2040 * Read @len bytes to @buffer from the I/O channel.
2041 *
2042 * Returns the number of bytes written
2043 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002044int
Owen Taylor3473f882001-02-23 17:55:21 +00002045xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002046 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002047 return(xmlNanoFTPRead(context, &buffer[0], len));
2048}
2049
2050/**
2051 * xmlIOFTPClose:
2052 * @context: the I/O context
2053 *
2054 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002055 *
2056 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002057 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002058int
Owen Taylor3473f882001-02-23 17:55:21 +00002059xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002060 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002061}
2062#endif /* LIBXML_FTP_ENABLED */
2063
2064
2065/**
2066 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002067 * @matchFunc: the xmlInputMatchCallback
2068 * @openFunc: the xmlInputOpenCallback
2069 * @readFunc: the xmlInputReadCallback
2070 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002071 *
2072 * Register a new set of I/O callback for handling parser input.
2073 *
2074 * Returns the registered handler number or -1 in case of error
2075 */
2076int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002077xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2078 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2079 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002080 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2081 return(-1);
2082 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002083 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2084 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2085 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2086 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002087 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002088 return(xmlInputCallbackNr++);
2089}
2090
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002091#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002092/**
2093 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002094 * @matchFunc: the xmlOutputMatchCallback
2095 * @openFunc: the xmlOutputOpenCallback
2096 * @writeFunc: the xmlOutputWriteCallback
2097 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002098 *
2099 * Register a new set of I/O callback for handling output.
2100 *
2101 * Returns the registered handler number or -1 in case of error
2102 */
2103int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002104xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2105 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2106 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002107 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2108 return(-1);
2109 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002110 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2111 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2112 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2113 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002114 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002115 return(xmlOutputCallbackNr++);
2116}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002117#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002118
2119/**
2120 * xmlRegisterDefaultInputCallbacks:
2121 *
2122 * Registers the default compiled-in I/O handlers.
2123 */
2124void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002125xmlRegisterDefaultInputCallbacks(void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002126 if (xmlInputCallbackInitialized)
2127 return;
2128
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002129#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2130 xmlInitPlatformSpecificIo();
2131#endif
2132
Owen Taylor3473f882001-02-23 17:55:21 +00002133 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2134 xmlFileRead, xmlFileClose);
2135#ifdef HAVE_ZLIB_H
2136 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2137 xmlGzfileRead, xmlGzfileClose);
2138#endif /* HAVE_ZLIB_H */
2139
2140#ifdef LIBXML_HTTP_ENABLED
2141 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2142 xmlIOHTTPRead, xmlIOHTTPClose);
2143#endif /* LIBXML_HTTP_ENABLED */
2144
2145#ifdef LIBXML_FTP_ENABLED
2146 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2147 xmlIOFTPRead, xmlIOFTPClose);
2148#endif /* LIBXML_FTP_ENABLED */
2149 xmlInputCallbackInitialized = 1;
2150}
2151
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002152#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002153/**
2154 * xmlRegisterDefaultOutputCallbacks:
2155 *
2156 * Registers the default compiled-in I/O handlers.
2157 */
2158void
Daniel Veillard6ad5c4a2006-10-11 16:43:06 +00002159xmlRegisterDefaultOutputCallbacks (void) {
Owen Taylor3473f882001-02-23 17:55:21 +00002160 if (xmlOutputCallbackInitialized)
2161 return;
2162
Daniel Veillard8ca85b22006-09-01 09:56:07 +00002163#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2164 xmlInitPlatformSpecificIo();
2165#endif
2166
Owen Taylor3473f882001-02-23 17:55:21 +00002167 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2168 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002169
2170#ifdef LIBXML_HTTP_ENABLED
2171 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2172 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2173#endif
2174
Owen Taylor3473f882001-02-23 17:55:21 +00002175/*********************************
2176 No way a-priori to distinguish between gzipped files from
2177 uncompressed ones except opening if existing then closing
2178 and saving with same compression ratio ... a pain.
2179
2180#ifdef HAVE_ZLIB_H
2181 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2182 xmlGzfileWrite, xmlGzfileClose);
2183#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002184
2185 Nor FTP PUT ....
2186#ifdef LIBXML_FTP_ENABLED
2187 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2188 xmlIOFTPWrite, xmlIOFTPClose);
2189#endif
2190 **********************************/
2191 xmlOutputCallbackInitialized = 1;
2192}
2193
Daniel Veillardf012a642001-07-23 19:10:52 +00002194#ifdef LIBXML_HTTP_ENABLED
2195/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002196 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002197 *
2198 * By default, libxml submits HTTP output requests using the "PUT" method.
2199 * Calling this method changes the HTTP output method to use the "POST"
2200 * method instead.
2201 *
2202 */
2203void
2204xmlRegisterHTTPPostCallbacks( void ) {
2205
2206 /* Register defaults if not done previously */
2207
2208 if ( xmlOutputCallbackInitialized == 0 )
2209 xmlRegisterDefaultOutputCallbacks( );
2210
2211 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2212 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2213 return;
2214}
2215#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002216#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002217
Owen Taylor3473f882001-02-23 17:55:21 +00002218/**
2219 * xmlAllocParserInputBuffer:
2220 * @enc: the charset encoding if known
2221 *
2222 * Create a buffered parser input for progressive parsing
2223 *
2224 * Returns the new parser input or NULL
2225 */
2226xmlParserInputBufferPtr
2227xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2228 xmlParserInputBufferPtr ret;
2229
2230 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2231 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002232 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002233 return(NULL);
2234 }
2235 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002236 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002237 if (ret->buffer == NULL) {
2238 xmlFree(ret);
2239 return(NULL);
2240 }
2241 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2242 ret->encoder = xmlGetCharEncodingHandler(enc);
2243 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002244 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002245 else
2246 ret->raw = NULL;
2247 ret->readcallback = NULL;
2248 ret->closecallback = NULL;
2249 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002250 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002251 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002252
2253 return(ret);
2254}
2255
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002256#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002257/**
2258 * xmlAllocOutputBuffer:
2259 * @encoder: the encoding converter or NULL
2260 *
2261 * Create a buffered parser output
2262 *
2263 * Returns the new parser output or NULL
2264 */
2265xmlOutputBufferPtr
2266xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2267 xmlOutputBufferPtr ret;
2268
2269 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2270 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002271 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002272 return(NULL);
2273 }
2274 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2275 ret->buffer = xmlBufferCreate();
2276 if (ret->buffer == NULL) {
2277 xmlFree(ret);
2278 return(NULL);
2279 }
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002280
Daniel Veillard43bc89c2009-03-23 19:32:04 +00002281 /* try to avoid a performance problem with Windows realloc() */
2282 if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT)
2283 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2284
Daniel Veillardda3fee42008-09-01 13:08:57 +00002285 ret->encoder = encoder;
2286 if (encoder != NULL) {
2287 ret->conv = xmlBufferCreateSize(4000);
2288 if (ret->conv == NULL) {
2289 xmlFree(ret);
2290 return(NULL);
2291 }
2292
2293 /*
2294 * This call is designed to initiate the encoder state
2295 */
2296 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2297 } else
2298 ret->conv = NULL;
2299 ret->writecallback = NULL;
2300 ret->closecallback = NULL;
2301 ret->context = NULL;
2302 ret->written = 0;
2303
2304 return(ret);
2305}
2306
2307/**
2308 * xmlAllocOutputBufferInternal:
2309 * @encoder: the encoding converter or NULL
2310 *
2311 * Create a buffered parser output
2312 *
2313 * Returns the new parser output or NULL
2314 */
2315xmlOutputBufferPtr
2316xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2317 xmlOutputBufferPtr ret;
2318
2319 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2320 if (ret == NULL) {
2321 xmlIOErrMemory("creating output buffer");
2322 return(NULL);
2323 }
2324 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2325 ret->buffer = xmlBufferCreate();
2326 if (ret->buffer == NULL) {
2327 xmlFree(ret);
2328 return(NULL);
2329 }
2330
2331
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002332 /*
2333 * For conversion buffers we use the special IO handling
Daniel Veillardda3fee42008-09-01 13:08:57 +00002334 * We don't do that from the exported API to avoid confusing
2335 * user's code.
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002336 */
2337 ret->buffer->alloc = XML_BUFFER_ALLOC_IO;
2338 ret->buffer->contentIO = ret->buffer->content;
2339
Owen Taylor3473f882001-02-23 17:55:21 +00002340 ret->encoder = encoder;
2341 if (encoder != NULL) {
2342 ret->conv = xmlBufferCreateSize(4000);
Daniel Veillarde83e93e2008-08-30 12:52:26 +00002343 if (ret->conv == NULL) {
2344 xmlFree(ret);
2345 return(NULL);
2346 }
2347
Owen Taylor3473f882001-02-23 17:55:21 +00002348 /*
2349 * This call is designed to initiate the encoder state
2350 */
2351 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2352 } else
2353 ret->conv = NULL;
2354 ret->writecallback = NULL;
2355 ret->closecallback = NULL;
2356 ret->context = NULL;
2357 ret->written = 0;
2358
2359 return(ret);
2360}
Daniel Veillardda3fee42008-09-01 13:08:57 +00002361
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002362#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002363
2364/**
2365 * xmlFreeParserInputBuffer:
2366 * @in: a buffered parser input
2367 *
2368 * Free up the memory used by a buffered parser input
2369 */
2370void
2371xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002372 if (in == NULL) return;
2373
Owen Taylor3473f882001-02-23 17:55:21 +00002374 if (in->raw) {
2375 xmlBufferFree(in->raw);
2376 in->raw = NULL;
2377 }
2378 if (in->encoder != NULL) {
2379 xmlCharEncCloseFunc(in->encoder);
2380 }
2381 if (in->closecallback != NULL) {
2382 in->closecallback(in->context);
2383 }
2384 if (in->buffer != NULL) {
2385 xmlBufferFree(in->buffer);
2386 in->buffer = NULL;
2387 }
2388
Owen Taylor3473f882001-02-23 17:55:21 +00002389 xmlFree(in);
2390}
2391
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002392#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002393/**
2394 * xmlOutputBufferClose:
2395 * @out: a buffered output
2396 *
2397 * flushes and close the output I/O channel
2398 * and free up all the associated resources
2399 *
2400 * Returns the number of byte written or -1 in case of error.
2401 */
2402int
Daniel Veillard828ce832003-10-08 19:19:10 +00002403xmlOutputBufferClose(xmlOutputBufferPtr out)
2404{
Owen Taylor3473f882001-02-23 17:55:21 +00002405 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002406 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002407
2408 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002409 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002410 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002411 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002412 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002413 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002414 }
2415 written = out->written;
2416 if (out->conv) {
2417 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002418 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002419 }
2420 if (out->encoder != NULL) {
2421 xmlCharEncCloseFunc(out->encoder);
2422 }
2423 if (out->buffer != NULL) {
2424 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002425 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002426 }
2427
Daniel Veillard828ce832003-10-08 19:19:10 +00002428 if (out->error)
2429 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002430 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002431 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002432}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002433#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002434
Daniel Veillard1b243b42004-06-08 10:16:42 +00002435xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002436__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002437 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002438 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002439 void *context = NULL;
2440
2441 if (xmlInputCallbackInitialized == 0)
2442 xmlRegisterDefaultInputCallbacks();
2443
2444 if (URI == NULL) return(NULL);
2445
2446 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002447 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002448 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002449 */
2450 if (context == NULL) {
2451 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2452 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2453 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002454 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002455 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002456 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002457 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002458 }
Owen Taylor3473f882001-02-23 17:55:21 +00002459 }
2460 }
2461 if (context == NULL) {
2462 return(NULL);
2463 }
2464
2465 /*
2466 * Allocate the Input buffer front-end.
2467 */
2468 ret = xmlAllocParserInputBuffer(enc);
2469 if (ret != NULL) {
2470 ret->context = context;
2471 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2472 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002473#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002474 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2475 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002476 if (((z_stream *)context)->avail_in > 4) {
2477 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002478 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002479 if (gzread(context, buff4, 4) == 4) {
2480 if (strncmp(buff4, cptr, 4) == 0)
2481 ret->compressed = 0;
2482 else
2483 ret->compressed = 1;
2484 gzrewind(context);
2485 }
2486 }
2487 }
2488#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002489 }
William M. Brack42331a92004-07-29 07:07:16 +00002490 else
2491 xmlInputCallbackTable[i].closecallback (context);
2492
Owen Taylor3473f882001-02-23 17:55:21 +00002493 return(ret);
2494}
2495
2496/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002497 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002498 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002499 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002500 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002501 * Create a buffered parser input for the progressive parsing of a file
2502 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002503 * Automatic support for ZLIB/Compress compressed document is provided
2504 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002505 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002506 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002507 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002508 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002509xmlParserInputBufferPtr
2510xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2511 if ((xmlParserInputBufferCreateFilenameValue)) {
2512 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2513 }
2514 return __xmlParserInputBufferCreateFilename(URI, enc);
2515}
2516
2517#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002518xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002519__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002520 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002521 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002522 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002523 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002524 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002525 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002526 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002527#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002528 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002529#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002530
Owen Taylor3473f882001-02-23 17:55:21 +00002531 if (xmlOutputCallbackInitialized == 0)
2532 xmlRegisterDefaultOutputCallbacks();
2533
2534 if (URI == NULL) return(NULL);
2535
Daniel Veillard966a31e2004-05-09 02:58:44 +00002536 puri = xmlParseURI(URI);
2537 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002538#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002539 if ((puri->scheme != NULL) &&
2540 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002541 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002542#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002543 /*
2544 * try to limit the damages of the URI unescaping code.
2545 */
Daniel Veillarde8967e02006-10-11 09:15:00 +00002546 if ((puri->scheme == NULL) ||
2547 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002548 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2549 xmlFreeURI(puri);
2550 }
Owen Taylor3473f882001-02-23 17:55:21 +00002551
2552 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002553 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002554 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002555 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002556 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002557 if (unescaped != NULL) {
2558#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002559 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002560 context = xmlGzfileOpenW(unescaped, compression);
2561 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002562 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002563 if (ret != NULL) {
2564 ret->context = context;
2565 ret->writecallback = xmlGzfileWrite;
2566 ret->closecallback = xmlGzfileClose;
2567 }
2568 xmlFree(unescaped);
2569 return(ret);
2570 }
2571 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002572#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002573 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2574 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2575 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2576#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2577 /* Need to pass compression parameter into HTTP open calls */
2578 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2579 context = xmlIOHTTPOpenW(unescaped, compression);
2580 else
2581#endif
2582 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2583 if (context != NULL)
2584 break;
2585 }
2586 }
2587 xmlFree(unescaped);
2588 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002589
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002590 /*
2591 * If this failed try with a non-escaped URI this may be a strange
2592 * filename
2593 */
2594 if (context == NULL) {
2595#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002596 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002597 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002598 if (context != NULL) {
Daniel Veillardda3fee42008-09-01 13:08:57 +00002599 ret = xmlAllocOutputBufferInternal(encoder);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002600 if (ret != NULL) {
2601 ret->context = context;
2602 ret->writecallback = xmlGzfileWrite;
2603 ret->closecallback = xmlGzfileClose;
2604 }
2605 return(ret);
2606 }
2607 }
2608#endif
2609 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2610 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002611 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002612#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2613 /* Need to pass compression parameter into HTTP open calls */
2614 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2615 context = xmlIOHTTPOpenW(URI, compression);
2616 else
2617#endif
2618 context = xmlOutputCallbackTable[i].opencallback(URI);
2619 if (context != NULL)
2620 break;
2621 }
Owen Taylor3473f882001-02-23 17:55:21 +00002622 }
2623 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002624
Owen Taylor3473f882001-02-23 17:55:21 +00002625 if (context == NULL) {
2626 return(NULL);
2627 }
2628
2629 /*
2630 * Allocate the Output buffer front-end.
2631 */
Daniel Veillardda3fee42008-09-01 13:08:57 +00002632 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002633 if (ret != NULL) {
2634 ret->context = context;
2635 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2636 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2637 }
2638 return(ret);
2639}
Daniel Veillard0335a842004-06-02 16:18:40 +00002640
2641/**
2642 * xmlOutputBufferCreateFilename:
2643 * @URI: a C string containing the URI or filename
2644 * @encoder: the encoding converter or NULL
2645 * @compression: the compression ration (0 none, 9 max).
2646 *
2647 * Create a buffered output for the progressive saving of a file
2648 * If filename is "-' then we use stdout as the output.
2649 * Automatic support for ZLIB/Compress compressed document is provided
2650 * by default if found at compile-time.
2651 * TODO: currently if compression is set, the library only support
2652 * writing to a local file.
2653 *
2654 * Returns the new output or NULL
2655 */
2656xmlOutputBufferPtr
2657xmlOutputBufferCreateFilename(const char *URI,
2658 xmlCharEncodingHandlerPtr encoder,
2659 int compression ATTRIBUTE_UNUSED) {
2660 if ((xmlOutputBufferCreateFilenameValue)) {
2661 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2662 }
2663 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2664}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002665#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002666
2667/**
2668 * xmlParserInputBufferCreateFile:
2669 * @file: a FILE*
2670 * @enc: the charset encoding if known
2671 *
2672 * Create a buffered parser input for the progressive parsing of a FILE *
2673 * buffered C I/O
2674 *
2675 * Returns the new parser input or NULL
2676 */
2677xmlParserInputBufferPtr
2678xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2679 xmlParserInputBufferPtr ret;
2680
2681 if (xmlInputCallbackInitialized == 0)
2682 xmlRegisterDefaultInputCallbacks();
2683
2684 if (file == NULL) return(NULL);
2685
2686 ret = xmlAllocParserInputBuffer(enc);
2687 if (ret != NULL) {
2688 ret->context = file;
2689 ret->readcallback = xmlFileRead;
2690 ret->closecallback = xmlFileFlush;
2691 }
2692
2693 return(ret);
2694}
2695
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002696#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002697/**
2698 * xmlOutputBufferCreateFile:
2699 * @file: a FILE*
2700 * @encoder: the encoding converter or NULL
2701 *
2702 * Create a buffered output for the progressive saving to a FILE *
2703 * buffered C I/O
2704 *
2705 * Returns the new parser output or NULL
2706 */
2707xmlOutputBufferPtr
2708xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2709 xmlOutputBufferPtr ret;
2710
2711 if (xmlOutputCallbackInitialized == 0)
2712 xmlRegisterDefaultOutputCallbacks();
2713
2714 if (file == NULL) return(NULL);
2715
Daniel Veillardda3fee42008-09-01 13:08:57 +00002716 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002717 if (ret != NULL) {
2718 ret->context = file;
2719 ret->writecallback = xmlFileWrite;
2720 ret->closecallback = xmlFileFlush;
2721 }
2722
2723 return(ret);
2724}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002725
2726/**
2727 * xmlOutputBufferCreateBuffer:
2728 * @buffer: a xmlBufferPtr
2729 * @encoder: the encoding converter or NULL
2730 *
2731 * Create a buffered output for the progressive saving to a xmlBuffer
2732 *
2733 * Returns the new parser output or NULL
2734 */
2735xmlOutputBufferPtr
2736xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2737 xmlCharEncodingHandlerPtr encoder) {
2738 xmlOutputBufferPtr ret;
2739
2740 if (buffer == NULL) return(NULL);
2741
Rob Richardsa44f2342005-11-09 18:03:45 +00002742 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2743 xmlBufferWrite,
2744 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002745 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002746
2747 return(ret);
2748}
2749
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002750#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002751
2752/**
2753 * xmlParserInputBufferCreateFd:
2754 * @fd: a file descriptor number
2755 * @enc: the charset encoding if known
2756 *
2757 * Create a buffered parser input for the progressive parsing for the input
2758 * from a file descriptor
2759 *
2760 * Returns the new parser input or NULL
2761 */
2762xmlParserInputBufferPtr
2763xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2764 xmlParserInputBufferPtr ret;
2765
2766 if (fd < 0) return(NULL);
2767
2768 ret = xmlAllocParserInputBuffer(enc);
2769 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002770 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002771 ret->readcallback = xmlFdRead;
2772 ret->closecallback = xmlFdClose;
2773 }
2774
2775 return(ret);
2776}
2777
2778/**
2779 * xmlParserInputBufferCreateMem:
2780 * @mem: the memory input
2781 * @size: the length of the memory block
2782 * @enc: the charset encoding if known
2783 *
2784 * Create a buffered parser input for the progressive parsing for the input
2785 * from a memory area.
2786 *
2787 * Returns the new parser input or NULL
2788 */
2789xmlParserInputBufferPtr
2790xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2791 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002792 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002793
2794 if (size <= 0) return(NULL);
2795 if (mem == NULL) return(NULL);
2796
2797 ret = xmlAllocParserInputBuffer(enc);
2798 if (ret != NULL) {
2799 ret->context = (void *) mem;
2800 ret->readcallback = (xmlInputReadCallback) xmlNop;
2801 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002802 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2803 if (errcode != 0) {
2804 xmlFree(ret);
2805 return(NULL);
2806 }
Owen Taylor3473f882001-02-23 17:55:21 +00002807 }
2808
2809 return(ret);
2810}
2811
2812/**
Daniel Veillard53350552003-09-18 13:35:51 +00002813 * xmlParserInputBufferCreateStatic:
2814 * @mem: the memory input
2815 * @size: the length of the memory block
2816 * @enc: the charset encoding if known
2817 *
2818 * Create a buffered parser input for the progressive parsing for the input
2819 * from an immutable memory area. This will not copy the memory area to
2820 * the buffer, but the memory is expected to be available until the end of
2821 * the parsing, this is useful for example when using mmap'ed file.
2822 *
2823 * Returns the new parser input or NULL
2824 */
2825xmlParserInputBufferPtr
2826xmlParserInputBufferCreateStatic(const char *mem, int size,
2827 xmlCharEncoding enc) {
2828 xmlParserInputBufferPtr ret;
2829
2830 if (size <= 0) return(NULL);
2831 if (mem == NULL) return(NULL);
2832
2833 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2834 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002835 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002836 return(NULL);
2837 }
2838 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002839 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002840 if (ret->buffer == NULL) {
2841 xmlFree(ret);
2842 return(NULL);
2843 }
2844 ret->encoder = xmlGetCharEncodingHandler(enc);
2845 if (ret->encoder != NULL)
2846 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2847 else
2848 ret->raw = NULL;
2849 ret->compressed = -1;
2850 ret->context = (void *) mem;
2851 ret->readcallback = NULL;
2852 ret->closecallback = NULL;
2853
2854 return(ret);
2855}
2856
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002857#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002858/**
Owen Taylor3473f882001-02-23 17:55:21 +00002859 * xmlOutputBufferCreateFd:
2860 * @fd: a file descriptor number
2861 * @encoder: the encoding converter or NULL
2862 *
2863 * Create a buffered output for the progressive saving
2864 * to a file descriptor
2865 *
2866 * Returns the new parser output or NULL
2867 */
2868xmlOutputBufferPtr
2869xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2870 xmlOutputBufferPtr ret;
2871
2872 if (fd < 0) return(NULL);
2873
Daniel Veillardda3fee42008-09-01 13:08:57 +00002874 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002875 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002876 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002877 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002878 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002879 }
2880
2881 return(ret);
2882}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002883#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002884
2885/**
2886 * xmlParserInputBufferCreateIO:
2887 * @ioread: an I/O read function
2888 * @ioclose: an I/O close function
2889 * @ioctx: an I/O handler
2890 * @enc: the charset encoding if known
2891 *
2892 * Create a buffered parser input for the progressive parsing for the input
2893 * from an I/O handler
2894 *
2895 * Returns the new parser input or NULL
2896 */
2897xmlParserInputBufferPtr
2898xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2899 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2900 xmlParserInputBufferPtr ret;
2901
2902 if (ioread == NULL) return(NULL);
2903
2904 ret = xmlAllocParserInputBuffer(enc);
2905 if (ret != NULL) {
2906 ret->context = (void *) ioctx;
2907 ret->readcallback = ioread;
2908 ret->closecallback = ioclose;
2909 }
2910
2911 return(ret);
2912}
2913
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002914#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002915/**
2916 * xmlOutputBufferCreateIO:
2917 * @iowrite: an I/O write function
2918 * @ioclose: an I/O close function
2919 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002920 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002921 *
2922 * Create a buffered output for the progressive saving
2923 * to an I/O handler
2924 *
2925 * Returns the new parser output or NULL
2926 */
2927xmlOutputBufferPtr
2928xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2929 xmlOutputCloseCallback ioclose, void *ioctx,
2930 xmlCharEncodingHandlerPtr encoder) {
2931 xmlOutputBufferPtr ret;
2932
2933 if (iowrite == NULL) return(NULL);
2934
Daniel Veillardda3fee42008-09-01 13:08:57 +00002935 ret = xmlAllocOutputBufferInternal(encoder);
Owen Taylor3473f882001-02-23 17:55:21 +00002936 if (ret != NULL) {
2937 ret->context = (void *) ioctx;
2938 ret->writecallback = iowrite;
2939 ret->closecallback = ioclose;
2940 }
2941
2942 return(ret);
2943}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002944#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002945
2946/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002947 * xmlParserInputBufferCreateFilenameDefault:
2948 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2949 *
2950 * Registers a callback for URI input file handling
2951 *
2952 * Returns the old value of the registration function
2953 */
2954xmlParserInputBufferCreateFilenameFunc
2955xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2956{
2957 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2958 if (old == NULL) {
2959 old = __xmlParserInputBufferCreateFilename;
2960 }
2961
2962 xmlParserInputBufferCreateFilenameValue = func;
2963 return(old);
2964}
2965
2966/**
2967 * xmlOutputBufferCreateFilenameDefault:
2968 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2969 *
2970 * Registers a callback for URI output file handling
2971 *
2972 * Returns the old value of the registration function
2973 */
2974xmlOutputBufferCreateFilenameFunc
2975xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2976{
2977 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2978#ifdef LIBXML_OUTPUT_ENABLED
2979 if (old == NULL) {
2980 old = __xmlOutputBufferCreateFilename;
2981 }
2982#endif
2983 xmlOutputBufferCreateFilenameValue = func;
2984 return(old);
2985}
2986
2987/**
Owen Taylor3473f882001-02-23 17:55:21 +00002988 * xmlParserInputBufferPush:
2989 * @in: a buffered parser input
2990 * @len: the size in bytes of the array.
2991 * @buf: an char array
2992 *
2993 * Push the content of the arry in the input buffer
2994 * This routine handle the I18N transcoding to internal UTF-8
2995 * This is used when operating the parser in progressive (push) mode.
2996 *
2997 * Returns the number of chars read and stored in the buffer, or -1
2998 * in case of error.
2999 */
3000int
3001xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3002 int len, const char *buf) {
3003 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00003004 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00003005
3006 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003007 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003008 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003009 unsigned int use;
3010
Owen Taylor3473f882001-02-23 17:55:21 +00003011 /*
3012 * Store the data in the incoming raw buffer
3013 */
3014 if (in->raw == NULL) {
3015 in->raw = xmlBufferCreate();
3016 }
William M. Bracka3215c72004-07-31 16:24:01 +00003017 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
3018 if (ret != 0)
3019 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003020
3021 /*
3022 * convert as much as possible to the parser reading buffer.
3023 */
Daniel Veillard36711902004-02-11 13:25:26 +00003024 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003025 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3026 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003027 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003028 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003029 return(-1);
3030 }
Daniel Veillard36711902004-02-11 13:25:26 +00003031 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003032 } else {
3033 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00003034 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
3035 if (ret != 0)
3036 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003037 }
3038#ifdef DEBUG_INPUT
3039 xmlGenericError(xmlGenericErrorContext,
3040 "I/O: pushed %d chars, buffer %d/%d\n",
3041 nbchars, in->buffer->use, in->buffer->size);
3042#endif
3043 return(nbchars);
3044}
3045
3046/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003047 * endOfInput:
3048 *
3049 * When reading from an Input channel indicated end of file or error
3050 * don't reread from it again.
3051 */
3052static int
3053endOfInput (void * context ATTRIBUTE_UNUSED,
3054 char * buffer ATTRIBUTE_UNUSED,
3055 int len ATTRIBUTE_UNUSED) {
3056 return(0);
3057}
3058
3059/**
Owen Taylor3473f882001-02-23 17:55:21 +00003060 * xmlParserInputBufferGrow:
3061 * @in: a buffered parser input
3062 * @len: indicative value of the amount of chars to read
3063 *
3064 * Grow up the content of the input buffer, the old data are preserved
3065 * This routine handle the I18N transcoding to internal UTF-8
3066 * This routine is used when operating the parser in normal (pull) mode
3067 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00003068 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00003069 * onto in->buffer or in->raw
3070 *
3071 * Returns the number of chars read and stored in the buffer, or -1
3072 * in case of error.
3073 */
3074int
3075xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3076 char *buffer = NULL;
3077 int res = 0;
3078 int nbchars = 0;
3079 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003080 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003081
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003082 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003083 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003084 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003085
Owen Taylor3473f882001-02-23 17:55:21 +00003086 buffree = in->buffer->size - in->buffer->use;
3087 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003088 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003089 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003090 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003091 }
Owen Taylor3473f882001-02-23 17:55:21 +00003092
Daniel Veillarde5354492002-05-16 08:43:22 +00003093 needSize = in->buffer->use + len + 1;
3094 if (needSize > in->buffer->size){
3095 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003096 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003097 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003098 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003099 }
Owen Taylor3473f882001-02-23 17:55:21 +00003100 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003101 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003102
3103 /*
3104 * Call the read method for this I/O type.
3105 */
3106 if (in->readcallback != NULL) {
3107 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003108 if (res <= 0)
3109 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003110 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003111 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003112 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003113 return(-1);
3114 }
3115 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003116 return(-1);
3117 }
3118 len = res;
3119 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003120 unsigned int use;
3121
Owen Taylor3473f882001-02-23 17:55:21 +00003122 /*
3123 * Store the data in the incoming raw buffer
3124 */
3125 if (in->raw == NULL) {
3126 in->raw = xmlBufferCreate();
3127 }
William M. Bracka3215c72004-07-31 16:24:01 +00003128 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3129 if (res != 0)
3130 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003131
3132 /*
3133 * convert as much as possible to the parser reading buffer.
3134 */
Daniel Veillard36711902004-02-11 13:25:26 +00003135 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003136 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3137 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003138 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003139 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003140 return(-1);
3141 }
Daniel Veillard36711902004-02-11 13:25:26 +00003142 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003143 } else {
3144 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003145 in->buffer->use += nbchars;
3146 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003147 }
3148#ifdef DEBUG_INPUT
3149 xmlGenericError(xmlGenericErrorContext,
3150 "I/O: read %d chars, buffer %d/%d\n",
3151 nbchars, in->buffer->use, in->buffer->size);
3152#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003153 return(nbchars);
3154}
3155
3156/**
3157 * xmlParserInputBufferRead:
3158 * @in: a buffered parser input
3159 * @len: indicative value of the amount of chars to read
3160 *
3161 * Refresh the content of the input buffer, the old data are considered
3162 * consumed
3163 * This routine handle the I18N transcoding to internal UTF-8
3164 *
3165 * Returns the number of chars read and stored in the buffer, or -1
3166 * in case of error.
3167 */
3168int
3169xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003170 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003171 if (in->readcallback != NULL)
3172 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003173 else if ((in->buffer != NULL) &&
3174 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3175 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003176 else
3177 return(-1);
3178}
3179
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003180#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003181/**
3182 * xmlOutputBufferWrite:
3183 * @out: a buffered parser output
3184 * @len: the size in bytes of the array.
3185 * @buf: an char array
3186 *
3187 * Write the content of the array in the output I/O buffer
3188 * This routine handle the I18N transcoding from internal UTF-8
3189 * The buffer is lossless, i.e. will store in case of partial
3190 * or delayed writes.
3191 *
3192 * Returns the number of chars immediately written, or -1
3193 * in case of error.
3194 */
3195int
3196xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3197 int nbchars = 0; /* number of chars to output to I/O */
3198 int ret; /* return from function call */
3199 int written = 0; /* number of char written to I/O so far */
3200 int chunk; /* number of byte curreent processed from buf */
3201
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003202 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003203 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003204 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003205
3206 do {
3207 chunk = len;
3208 if (chunk > 4 * MINLEN)
3209 chunk = 4 * MINLEN;
3210
3211 /*
3212 * first handle encoding stuff.
3213 */
3214 if (out->encoder != NULL) {
3215 /*
3216 * Store the data in the incoming raw buffer
3217 */
3218 if (out->conv == NULL) {
3219 out->conv = xmlBufferCreate();
3220 }
William M. Bracka3215c72004-07-31 16:24:01 +00003221 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3222 if (ret != 0)
3223 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003224
3225 if ((out->buffer->use < MINLEN) && (chunk == len))
3226 goto done;
3227
3228 /*
3229 * convert as much as possible to the parser reading buffer.
3230 */
3231 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003232 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003233 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003234 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003235 return(-1);
3236 }
3237 nbchars = out->conv->use;
3238 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003239 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3240 if (ret != 0)
3241 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003242 nbchars = out->buffer->use;
3243 }
3244 buf += chunk;
3245 len -= chunk;
3246
3247 if ((nbchars < MINLEN) && (len <= 0))
3248 goto done;
3249
3250 if (out->writecallback) {
3251 /*
3252 * second write the stuff to the I/O channel
3253 */
3254 if (out->encoder != NULL) {
3255 ret = out->writecallback(out->context,
3256 (const char *)out->conv->content, nbchars);
3257 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003258 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003259 } else {
3260 ret = out->writecallback(out->context,
3261 (const char *)out->buffer->content, nbchars);
3262 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003263 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003264 }
3265 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003266 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003267 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003268 return(ret);
3269 }
3270 out->written += ret;
3271 }
3272 written += nbchars;
3273 } while (len > 0);
3274
3275done:
3276#ifdef DEBUG_INPUT
3277 xmlGenericError(xmlGenericErrorContext,
3278 "I/O: wrote %d chars\n", written);
3279#endif
3280 return(written);
3281}
3282
3283/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003284 * xmlEscapeContent:
3285 * @out: a pointer to an array of bytes to store the result
3286 * @outlen: the length of @out
3287 * @in: a pointer to an array of unescaped UTF-8 bytes
3288 * @inlen: the length of @in
3289 *
3290 * Take a block of UTF-8 chars in and escape them.
3291 * Returns 0 if success, or -1 otherwise
3292 * The value of @inlen after return is the number of octets consumed
3293 * if the return value is positive, else unpredictable.
3294 * The value of @outlen after return is the number of octets consumed.
3295 */
3296static int
3297xmlEscapeContent(unsigned char* out, int *outlen,
3298 const xmlChar* in, int *inlen) {
3299 unsigned char* outstart = out;
3300 const unsigned char* base = in;
3301 unsigned char* outend = out + *outlen;
3302 const unsigned char* inend;
3303
3304 inend = in + (*inlen);
3305
3306 while ((in < inend) && (out < outend)) {
3307 if (*in == '<') {
3308 if (outend - out < 4) break;
3309 *out++ = '&';
3310 *out++ = 'l';
3311 *out++ = 't';
3312 *out++ = ';';
3313 } else if (*in == '>') {
3314 if (outend - out < 4) break;
3315 *out++ = '&';
3316 *out++ = 'g';
3317 *out++ = 't';
3318 *out++ = ';';
3319 } else if (*in == '&') {
3320 if (outend - out < 5) break;
3321 *out++ = '&';
3322 *out++ = 'a';
3323 *out++ = 'm';
3324 *out++ = 'p';
3325 *out++ = ';';
3326 } else if (*in == '\r') {
3327 if (outend - out < 5) break;
3328 *out++ = '&';
3329 *out++ = '#';
3330 *out++ = '1';
3331 *out++ = '3';
3332 *out++ = ';';
3333 } else {
3334 *out++ = (unsigned char) *in;
3335 }
3336 ++in;
3337 }
3338 *outlen = out - outstart;
3339 *inlen = in - base;
3340 return(0);
3341}
3342
3343/**
3344 * xmlOutputBufferWriteEscape:
3345 * @out: a buffered parser output
3346 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003347 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003348 *
3349 * Write the content of the string in the output I/O buffer
3350 * This routine escapes the caracters and then handle the I18N
3351 * transcoding from internal UTF-8
3352 * The buffer is lossless, i.e. will store in case of partial
3353 * or delayed writes.
3354 *
3355 * Returns the number of chars immediately written, or -1
3356 * in case of error.
3357 */
3358int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003359xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3360 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003361 int nbchars = 0; /* number of chars to output to I/O */
3362 int ret; /* return from function call */
3363 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003364 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003365 int chunk; /* number of byte currently processed from str */
3366 int len; /* number of bytes in str */
3367 int cons; /* byte from str consumed */
3368
Daniel Veillardce244ad2004-11-05 10:03:46 +00003369 if ((out == NULL) || (out->error) || (str == NULL) ||
3370 (out->buffer == NULL) ||
3371 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003372 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003373 if (len < 0) return(0);
3374 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003375 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003376
3377 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003378 oldwritten = written;
3379
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003380 /*
3381 * how many bytes to consume and how many bytes to store.
3382 */
3383 cons = len;
3384 chunk = (out->buffer->size - out->buffer->use) - 1;
3385
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003386 /*
3387 * make sure we have enough room to save first, if this is
3388 * not the case force a flush, but make sure we stay in the loop
3389 */
3390 if (chunk < 40) {
Daniel Veillarde83e93e2008-08-30 12:52:26 +00003391 if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0)
3392 return(-1);
3393 oldwritten = -1;
3394 continue;
Daniel Veillardc4ba8a42008-02-16 10:08:14 +00003395 }
3396
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003397 /*
3398 * first handle encoding stuff.
3399 */
3400 if (out->encoder != NULL) {
3401 /*
3402 * Store the data in the incoming raw buffer
3403 */
3404 if (out->conv == NULL) {
3405 out->conv = xmlBufferCreate();
3406 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003407 ret = escaping(out->buffer->content + out->buffer->use ,
3408 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003409 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003410 return(-1);
3411 out->buffer->use += chunk;
3412 out->buffer->content[out->buffer->use] = 0;
3413
3414 if ((out->buffer->use < MINLEN) && (cons == len))
3415 goto done;
3416
3417 /*
3418 * convert as much as possible to the output buffer.
3419 */
3420 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3421 if ((ret < 0) && (ret != -3)) {
3422 xmlIOErr(XML_IO_ENCODER, NULL);
3423 out->error = XML_IO_ENCODER;
3424 return(-1);
3425 }
3426 nbchars = out->conv->use;
3427 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003428 ret = escaping(out->buffer->content + out->buffer->use ,
3429 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003430 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003431 return(-1);
3432 out->buffer->use += chunk;
3433 out->buffer->content[out->buffer->use] = 0;
3434 nbchars = out->buffer->use;
3435 }
3436 str += cons;
3437 len -= cons;
3438
3439 if ((nbchars < MINLEN) && (len <= 0))
3440 goto done;
3441
3442 if (out->writecallback) {
3443 /*
3444 * second write the stuff to the I/O channel
3445 */
3446 if (out->encoder != NULL) {
3447 ret = out->writecallback(out->context,
3448 (const char *)out->conv->content, nbchars);
3449 if (ret >= 0)
3450 xmlBufferShrink(out->conv, ret);
3451 } else {
3452 ret = out->writecallback(out->context,
3453 (const char *)out->buffer->content, nbchars);
3454 if (ret >= 0)
3455 xmlBufferShrink(out->buffer, ret);
3456 }
3457 if (ret < 0) {
3458 xmlIOErr(XML_IO_WRITE, NULL);
3459 out->error = XML_IO_WRITE;
3460 return(ret);
3461 }
3462 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003463 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3464 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003465 }
3466 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003467 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003468
3469done:
3470#ifdef DEBUG_INPUT
3471 xmlGenericError(xmlGenericErrorContext,
3472 "I/O: wrote %d chars\n", written);
3473#endif
3474 return(written);
3475}
3476
3477/**
Owen Taylor3473f882001-02-23 17:55:21 +00003478 * xmlOutputBufferWriteString:
3479 * @out: a buffered parser output
3480 * @str: a zero terminated C string
3481 *
3482 * Write the content of the string in the output I/O buffer
3483 * This routine handle the I18N transcoding from internal UTF-8
3484 * The buffer is lossless, i.e. will store in case of partial
3485 * or delayed writes.
3486 *
3487 * Returns the number of chars immediately written, or -1
3488 * in case of error.
3489 */
3490int
3491xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3492 int len;
3493
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003494 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003495 if (str == NULL)
3496 return(-1);
3497 len = strlen(str);
3498
3499 if (len > 0)
3500 return(xmlOutputBufferWrite(out, len, str));
3501 return(len);
3502}
3503
3504/**
3505 * xmlOutputBufferFlush:
3506 * @out: a buffered output
3507 *
3508 * flushes the output I/O channel
3509 *
3510 * Returns the number of byte written or -1 in case of error.
3511 */
3512int
3513xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3514 int nbchars = 0, ret = 0;
3515
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003516 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003517 /*
3518 * first handle encoding stuff.
3519 */
3520 if ((out->conv != NULL) && (out->encoder != NULL)) {
3521 /*
3522 * convert as much as possible to the parser reading buffer.
3523 */
3524 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3525 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003526 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003527 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003528 return(-1);
3529 }
3530 }
3531
3532 /*
3533 * second flush the stuff to the I/O channel
3534 */
3535 if ((out->conv != NULL) && (out->encoder != NULL) &&
3536 (out->writecallback != NULL)) {
3537 ret = out->writecallback(out->context,
3538 (const char *)out->conv->content, out->conv->use);
3539 if (ret >= 0)
3540 xmlBufferShrink(out->conv, ret);
3541 } else if (out->writecallback != NULL) {
3542 ret = out->writecallback(out->context,
3543 (const char *)out->buffer->content, out->buffer->use);
3544 if (ret >= 0)
3545 xmlBufferShrink(out->buffer, ret);
3546 }
3547 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003548 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003549 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003550 return(ret);
3551 }
3552 out->written += ret;
3553
3554#ifdef DEBUG_INPUT
3555 xmlGenericError(xmlGenericErrorContext,
3556 "I/O: flushed %d chars\n", ret);
3557#endif
3558 return(ret);
3559}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003560#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003561
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003562/**
Owen Taylor3473f882001-02-23 17:55:21 +00003563 * xmlParserGetDirectory:
3564 * @filename: the path to a file
3565 *
3566 * lookup the directory for that file
3567 *
3568 * Returns a new allocated string containing the directory, or NULL.
3569 */
3570char *
3571xmlParserGetDirectory(const char *filename) {
3572 char *ret = NULL;
3573 char dir[1024];
3574 char *cur;
Owen Taylor3473f882001-02-23 17:55:21 +00003575
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003576#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3577 return NULL;
3578#endif
3579
Owen Taylor3473f882001-02-23 17:55:21 +00003580 if (xmlInputCallbackInitialized == 0)
3581 xmlRegisterDefaultInputCallbacks();
3582
3583 if (filename == NULL) return(NULL);
Rob Richardsf779da32007-08-14 09:41:21 +00003584
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003585#if defined(WIN32) && !defined(__CYGWIN__)
Rob Richardsf779da32007-08-14 09:41:21 +00003586# define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3587#else
3588# define IS_XMLPGD_SEP(ch) (ch=='/')
Owen Taylor3473f882001-02-23 17:55:21 +00003589#endif
3590
3591 strncpy(dir, filename, 1023);
3592 dir[1023] = 0;
3593 cur = &dir[strlen(dir)];
3594 while (cur > dir) {
Rob Richardsf779da32007-08-14 09:41:21 +00003595 if (IS_XMLPGD_SEP(*cur)) break;
Owen Taylor3473f882001-02-23 17:55:21 +00003596 cur --;
3597 }
Rob Richardsf779da32007-08-14 09:41:21 +00003598 if (IS_XMLPGD_SEP(*cur)) {
Owen Taylor3473f882001-02-23 17:55:21 +00003599 if (cur == dir) dir[1] = 0;
3600 else *cur = 0;
3601 ret = xmlMemStrdup(dir);
3602 } else {
3603 if (getcwd(dir, 1024) != NULL) {
3604 dir[1023] = 0;
3605 ret = xmlMemStrdup(dir);
3606 }
3607 }
3608 return(ret);
Rob Richardsf779da32007-08-14 09:41:21 +00003609#undef IS_XMLPGD_SEP
Owen Taylor3473f882001-02-23 17:55:21 +00003610}
3611
3612/****************************************************************
3613 * *
3614 * External entities loading *
3615 * *
3616 ****************************************************************/
3617
Daniel Veillarda840b692003-10-19 13:35:37 +00003618/**
3619 * xmlCheckHTTPInput:
3620 * @ctxt: an XML parser context
3621 * @ret: an XML parser input
3622 *
3623 * Check an input in case it was created from an HTTP stream, in that
3624 * case it will handle encoding and update of the base URL in case of
3625 * redirection. It also checks for HTTP errors in which case the input
3626 * is cleanly freed up and an appropriate error is raised in context
3627 *
3628 * Returns the input or NULL in case of HTTP error.
3629 */
3630xmlParserInputPtr
3631xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3632#ifdef LIBXML_HTTP_ENABLED
3633 if ((ret != NULL) && (ret->buf != NULL) &&
3634 (ret->buf->readcallback == xmlIOHTTPRead) &&
3635 (ret->buf->context != NULL)) {
3636 const char *encoding;
3637 const char *redir;
3638 const char *mime;
3639 int code;
3640
3641 code = xmlNanoHTTPReturnCode(ret->buf->context);
3642 if (code >= 400) {
3643 /* fatal error */
3644 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003645 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003646 (const char *) ret->filename);
3647 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003648 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003649 xmlFreeInputStream(ret);
3650 ret = NULL;
3651 } else {
3652
3653 mime = xmlNanoHTTPMimeType(ret->buf->context);
3654 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3655 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3656 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3657 if (encoding != NULL) {
3658 xmlCharEncodingHandlerPtr handler;
3659
3660 handler = xmlFindCharEncodingHandler(encoding);
3661 if (handler != NULL) {
3662 xmlSwitchInputEncoding(ctxt, ret, handler);
3663 } else {
3664 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3665 "Unknown encoding %s",
3666 BAD_CAST encoding, NULL);
3667 }
3668 if (ret->encoding == NULL)
3669 ret->encoding = xmlStrdup(BAD_CAST encoding);
3670 }
3671#if 0
3672 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3673#endif
3674 }
3675 redir = xmlNanoHTTPRedir(ret->buf->context);
3676 if (redir != NULL) {
3677 if (ret->filename != NULL)
3678 xmlFree((xmlChar *) ret->filename);
3679 if (ret->directory != NULL) {
3680 xmlFree((xmlChar *) ret->directory);
3681 ret->directory = NULL;
3682 }
3683 ret->filename =
3684 (char *) xmlStrdup((const xmlChar *) redir);
3685 }
3686 }
3687 }
3688#endif
3689 return(ret);
3690}
3691
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003692static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003693 const char *path;
3694
3695 if (URL == NULL)
3696 return(0);
3697
Daniel Veillardf4862f02002-09-10 11:13:43 +00003698 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003699#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003700 path = &URL[17];
3701#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003702 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003703#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003704 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003705#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003706 path = &URL[8];
3707#else
3708 path = &URL[7];
3709#endif
3710 } else
3711 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003712
3713 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003714}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003715
Daniel Veillardad4e2962006-09-21 08:36:38 +00003716#ifdef LIBXML_CATALOG_ENABLED
3717
3718/**
3719 * xmlResolveResourceFromCatalog:
3720 * @URL: the URL for the entity to load
3721 * @ID: the System ID for the entity to load
3722 * @ctxt: the context in which the entity is called or NULL
3723 *
3724 * Resolves the URL and ID against the appropriate catalog.
3725 * This function is used by xmlDefaultExternalEntityLoader and
3726 * xmlNoNetExternalEntityLoader.
3727 *
3728 * Returns a new allocated URL, or NULL.
3729 */
William M. Brack38d452a2007-05-22 16:00:06 +00003730static xmlChar *
Daniel Veillardad4e2962006-09-21 08:36:38 +00003731xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3732 xmlParserCtxtPtr ctxt) {
3733 xmlChar *resource = NULL;
3734 xmlCatalogAllow pref;
3735
3736 /*
3737 * If the resource doesn't exists as a file,
3738 * try to load it from the resource pointed in the catalogs
3739 */
3740 pref = xmlCatalogGetDefaults();
3741
3742 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3743 /*
3744 * Do a local lookup
3745 */
3746 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3747 ((pref == XML_CATA_ALLOW_ALL) ||
3748 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3749 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3750 (const xmlChar *)ID,
3751 (const xmlChar *)URL);
3752 }
3753 /*
3754 * Try a global lookup
3755 */
3756 if ((resource == NULL) &&
3757 ((pref == XML_CATA_ALLOW_ALL) ||
3758 (pref == XML_CATA_ALLOW_GLOBAL))) {
3759 resource = xmlCatalogResolve((const xmlChar *)ID,
3760 (const xmlChar *)URL);
3761 }
3762 if ((resource == NULL) && (URL != NULL))
3763 resource = xmlStrdup((const xmlChar *) URL);
3764
3765 /*
3766 * TODO: do an URI lookup on the reference
3767 */
3768 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3769 xmlChar *tmp = NULL;
3770
3771 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3772 ((pref == XML_CATA_ALLOW_ALL) ||
3773 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3774 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3775 }
3776 if ((tmp == NULL) &&
3777 ((pref == XML_CATA_ALLOW_ALL) ||
3778 (pref == XML_CATA_ALLOW_GLOBAL))) {
3779 tmp = xmlCatalogResolveURI(resource);
3780 }
3781
3782 if (tmp != NULL) {
3783 xmlFree(resource);
3784 resource = tmp;
3785 }
3786 }
3787 }
3788
3789 return resource;
3790}
3791
3792#endif
3793
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003794/**
Owen Taylor3473f882001-02-23 17:55:21 +00003795 * xmlDefaultExternalEntityLoader:
3796 * @URL: the URL for the entity to load
3797 * @ID: the System ID for the entity to load
3798 * @ctxt: the context in which the entity is called or NULL
3799 *
3800 * By default we don't load external entitites, yet.
3801 *
3802 * Returns a new allocated xmlParserInputPtr, or NULL.
3803 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003804static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003805xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003806 xmlParserCtxtPtr ctxt)
3807{
Owen Taylor3473f882001-02-23 17:55:21 +00003808 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003809 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003810
Owen Taylor3473f882001-02-23 17:55:21 +00003811#ifdef DEBUG_EXTERNAL_ENTITIES
3812 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003813 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003814#endif
Daniel Veillard61b93382003-11-03 14:28:31 +00003815 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3816 int options = ctxt->options;
3817
3818 ctxt->options -= XML_PARSE_NONET;
3819 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3820 ctxt->options = options;
3821 return(ret);
3822 }
Daniel Veillardad4e2962006-09-21 08:36:38 +00003823#ifdef LIBXML_CATALOG_ENABLED
3824 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003825#endif
3826
3827 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003828 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003829
3830 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003831 if (ID == NULL)
3832 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003833 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003834 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003835 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003836 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003837 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003838 xmlFree(resource);
3839 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003840}
3841
3842static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3843 xmlDefaultExternalEntityLoader;
3844
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003845/**
Owen Taylor3473f882001-02-23 17:55:21 +00003846 * xmlSetExternalEntityLoader:
3847 * @f: the new entity resolver function
3848 *
3849 * Changes the defaultexternal entity resolver function for the application
3850 */
3851void
3852xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3853 xmlCurrentExternalEntityLoader = f;
3854}
3855
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003856/**
Owen Taylor3473f882001-02-23 17:55:21 +00003857 * xmlGetExternalEntityLoader:
3858 *
3859 * Get the default external entity resolver function for the application
3860 *
3861 * Returns the xmlExternalEntityLoader function pointer
3862 */
3863xmlExternalEntityLoader
3864xmlGetExternalEntityLoader(void) {
3865 return(xmlCurrentExternalEntityLoader);
3866}
3867
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003868/**
Owen Taylor3473f882001-02-23 17:55:21 +00003869 * xmlLoadExternalEntity:
3870 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003871 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003872 * @ctxt: the context in which the entity is called or NULL
3873 *
3874 * Load an external entity, note that the use of this function for
3875 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003876 *
3877 * Returns the xmlParserInputPtr or NULL
3878 */
3879xmlParserInputPtr
3880xmlLoadExternalEntity(const char *URL, const char *ID,
3881 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003882 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003883 char *canonicFilename;
3884 xmlParserInputPtr ret;
3885
3886 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3887 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003888 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003889 return(NULL);
3890 }
3891
3892 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3893 xmlFree(canonicFilename);
3894 return(ret);
3895 }
Owen Taylor3473f882001-02-23 17:55:21 +00003896 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3897}
3898
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003899/************************************************************************
3900 * *
3901 * Disabling Network access *
3902 * *
3903 ************************************************************************/
3904
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003905/**
3906 * xmlNoNetExternalEntityLoader:
3907 * @URL: the URL for the entity to load
3908 * @ID: the System ID for the entity to load
3909 * @ctxt: the context in which the entity is called or NULL
3910 *
3911 * A specific entity loader disabling network accesses, though still
3912 * allowing local catalog accesses for resolution.
3913 *
3914 * Returns a new allocated xmlParserInputPtr, or NULL.
3915 */
3916xmlParserInputPtr
3917xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3918 xmlParserCtxtPtr ctxt) {
3919 xmlParserInputPtr input = NULL;
3920 xmlChar *resource = NULL;
3921
3922#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillardad4e2962006-09-21 08:36:38 +00003923 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003924#endif
Daniel Veillardad4e2962006-09-21 08:36:38 +00003925
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003926 if (resource == NULL)
3927 resource = (xmlChar *) URL;
3928
3929 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003930 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3931 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003932 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003933 if (resource != (xmlChar *) URL)
3934 xmlFree(resource);
3935 return(NULL);
3936 }
3937 }
3938 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3939 if (resource != (xmlChar *) URL)
3940 xmlFree(resource);
3941 return(input);
3942}
3943
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003944#define bottom_xmlIO
3945#include "elfgcchack.h"