blob: 58b3febfc7b2e7b89dfcf04dc51b56b0fdf7a657 [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 Veillardf7416012006-04-27 08:15:20 +000039#ifdef WIN32
40#include <windows.h>
41#endif
42
Owen Taylor3473f882001-02-23 17:55:21 +000043/* Figure a portable way to know if a file is a directory. */
44#ifndef HAVE_STAT
45# ifdef HAVE__STAT
Daniel Veillard50f34372001-08-03 12:06:36 +000046 /* MS C library seems to define stat and _stat. The definition
47 is identical. Still, mapping them to each other causes a warning. */
48# ifndef _MSC_VER
49# define stat(x,y) _stat(x,y)
50# endif
Owen Taylor3473f882001-02-23 17:55:21 +000051# define HAVE_STAT
52# endif
53#endif
54#ifdef HAVE_STAT
55# ifndef S_ISDIR
56# ifdef _S_ISDIR
57# define S_ISDIR(x) _S_ISDIR(x)
58# else
59# ifdef S_IFDIR
60# ifndef S_IFMT
61# ifdef _S_IFMT
62# define S_IFMT _S_IFMT
63# endif
64# endif
65# ifdef S_IFMT
66# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
67# endif
68# endif
69# endif
70# endif
71#endif
72
73#include <libxml/xmlmemory.h>
74#include <libxml/parser.h>
75#include <libxml/parserInternals.h>
76#include <libxml/xmlIO.h>
Daniel Veillard388236f2001-07-08 18:35:48 +000077#include <libxml/uri.h>
Owen Taylor3473f882001-02-23 17:55:21 +000078#include <libxml/nanohttp.h>
79#include <libxml/nanoftp.h>
80#include <libxml/xmlerror.h>
Daniel Veillard7d6fd212001-05-10 15:34:11 +000081#ifdef LIBXML_CATALOG_ENABLED
82#include <libxml/catalog.h>
83#endif
Daniel Veillard3c01b1d2001-10-17 15:58:35 +000084#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000085
Daniel Veillardf012a642001-07-23 19:10:52 +000086/* #define VERBOSE_FAILURE */
Daniel Veillard1fd36d22001-07-04 22:54:28 +000087/* #define DEBUG_EXTERNAL_ENTITIES */
Owen Taylor3473f882001-02-23 17:55:21 +000088/* #define DEBUG_INPUT */
89
90#ifdef DEBUG_INPUT
91#define MINLEN 40
92#else
93#define MINLEN 4000
94#endif
95
96/*
97 * Input I/O callback sets
98 */
99typedef struct _xmlInputCallback {
100 xmlInputMatchCallback matchcallback;
101 xmlInputOpenCallback opencallback;
102 xmlInputReadCallback readcallback;
103 xmlInputCloseCallback closecallback;
104} xmlInputCallback;
105
106#define MAX_INPUT_CALLBACK 15
107
Daniel Veillard22090732001-07-16 00:06:07 +0000108static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
109static int xmlInputCallbackNr = 0;
110static int xmlInputCallbackInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000111
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000112#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000113/*
114 * Output I/O callback sets
115 */
116typedef struct _xmlOutputCallback {
117 xmlOutputMatchCallback matchcallback;
118 xmlOutputOpenCallback opencallback;
119 xmlOutputWriteCallback writecallback;
120 xmlOutputCloseCallback closecallback;
121} xmlOutputCallback;
122
123#define MAX_OUTPUT_CALLBACK 15
124
Daniel Veillard22090732001-07-16 00:06:07 +0000125static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
126static int xmlOutputCallbackNr = 0;
127static int xmlOutputCallbackInitialized = 0;
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000128#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000129
Daniel Veillard05d987b2003-10-08 11:54:57 +0000130/************************************************************************
131 * *
132 * Tree memory error handler *
133 * *
134 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000135
Daniel Veillard05d987b2003-10-08 11:54:57 +0000136static const char *IOerr[] = {
Daniel Veillarda8856222003-10-08 19:26:03 +0000137 "Unknown IO error", /* UNKNOWN */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000138 "Permission denied", /* EACCES */
139 "Resource temporarily unavailable",/* EAGAIN */
140 "Bad file descriptor", /* EBADF */
141 "Bad message", /* EBADMSG */
142 "Resource busy", /* EBUSY */
143 "Operation canceled", /* ECANCELED */
144 "No child processes", /* ECHILD */
145 "Resource deadlock avoided",/* EDEADLK */
146 "Domain error", /* EDOM */
147 "File exists", /* EEXIST */
148 "Bad address", /* EFAULT */
149 "File too large", /* EFBIG */
150 "Operation in progress", /* EINPROGRESS */
151 "Interrupted function call",/* EINTR */
152 "Invalid argument", /* EINVAL */
153 "Input/output error", /* EIO */
154 "Is a directory", /* EISDIR */
155 "Too many open files", /* EMFILE */
156 "Too many links", /* EMLINK */
157 "Inappropriate message buffer length",/* EMSGSIZE */
158 "Filename too long", /* ENAMETOOLONG */
159 "Too many open files in system",/* ENFILE */
160 "No such device", /* ENODEV */
161 "No such file or directory",/* ENOENT */
162 "Exec format error", /* ENOEXEC */
163 "No locks available", /* ENOLCK */
164 "Not enough space", /* ENOMEM */
165 "No space left on device", /* ENOSPC */
166 "Function not implemented", /* ENOSYS */
167 "Not a directory", /* ENOTDIR */
168 "Directory not empty", /* ENOTEMPTY */
169 "Not supported", /* ENOTSUP */
170 "Inappropriate I/O control operation",/* ENOTTY */
171 "No such device or address",/* ENXIO */
172 "Operation not permitted", /* EPERM */
173 "Broken pipe", /* EPIPE */
174 "Result too large", /* ERANGE */
175 "Read-only file system", /* EROFS */
176 "Invalid seek", /* ESPIPE */
177 "No such process", /* ESRCH */
178 "Operation timed out", /* ETIMEDOUT */
179 "Improper link", /* EXDEV */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000180 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000181 "encoder error", /* XML_IO_ENCODER */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000182 "flush error",
183 "write error",
184 "no input",
185 "buffer full",
186 "loading error",
187 "not a socket", /* ENOTSOCK */
188 "already connected", /* EISCONN */
Daniel Veillard29b17482004-08-16 00:39:03 +0000189 "connection refused", /* ECONNREFUSED */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000190 "unreachable network", /* ENETUNREACH */
191 "adddress in use", /* EADDRINUSE */
192 "already in use", /* EALREADY */
193 "unknown address familly", /* EAFNOSUPPORT */
Daniel Veillard05d987b2003-10-08 11:54:57 +0000194};
195
Daniel Veillardf7416012006-04-27 08:15:20 +0000196#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
197/**
198 * __xmlIOWin32UTF8ToWChar:
199 * @u8String: uft-8 string
200 *
201 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
202 */
203static wchar_t *
204__xmlIOWin32UTF8ToWChar(const char *u8String)
205{
206 wchar_t *wString = NULL;
207
208 if (u8String)
209 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000210 int wLen = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,u8String,-1,NULL,0);
Daniel Veillardf7416012006-04-27 08:15:20 +0000211 if (wLen)
212 {
213 wString = malloc((wLen+1) * sizeof(wchar_t));
214 if (wString)
215 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000216 if (MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,u8String,-1,wString,wLen+1) == 0)
Daniel Veillardf7416012006-04-27 08:15:20 +0000217 {
218 free(wString);
219 wString = NULL;
220 }
221 }
222 }
223 }
224
225 return wString;
226}
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000227
228/**
229 * __xmlIOWin32GetWcharFunc:
230 * @name: name of function
231 *
232 * returns function pointer to certain wide character functions
233 * contained in msvcrt.dll on Windows NT or better.
234 * There is no (really working) support for it on win95/98/Me
235 * but to retain compatibility on ascii basis the capabilities
236 * of the os are depicted during runtime (see use of this function in this file)
237 */
238static void *
239__xmlIOWin32GetWcharFunc(const char *name)
240{
241 void *function = NULL;
242 static HANDLE msvcrt = INVALID_HANDLE_VALUE;
243 static HANDLE winMutex = INVALID_HANDLE_VALUE;
244
245 // create Mutex if not already there
246 if (winMutex == INVALID_HANDLE_VALUE)
247 {
248 winMutex = CreateMutexA(NULL, FALSE, "__xmlIOWin32GetWcharFunc mutex");
249 if (!winMutex)
250 return NULL;
251 }
252
253 // Be atomic
254 if (WaitForSingleObject(winMutex, INFINITE) == WAIT_OBJECT_0)
255 {
256 if (msvcrt == INVALID_HANDLE_VALUE)
257 {
258 msvcrt = NULL; // ensure to enter this code just once
259 OSVERSIONINFOEX osvi;
260
261 ZeroMemory(&osvi,sizeof(OSVERSIONINFOEX));
262 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
263
264 // Get Operatingsystemversion. If something is wrong here, the system
265 // is heavily damaged. Refuse to deliver pointers in this case.
266 if (!GetVersionEx((OSVERSIONINFO *)&osvi))
267 {
268 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
269 if (!GetVersionEx((OSVERSIONINFO *)&osvi))
270 {
271 ReleaseMutex(winMutex);
272 return NULL;
273 }
274 }
275
276 // Only continue on NT or better
277 if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)
278 {
279 unsigned int oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
280
281 msvcrt = LoadLibraryA("msvcrt.dll");
282 SetErrorMode(oldErrorMode);
283 }
284 }
285
286 if (msvcrt && name)
287 function = (void *)GetProcAddress(msvcrt,name);
288
289 ReleaseMutex(winMutex);
290 }
291
292 return function;
293}
Daniel Veillardf7416012006-04-27 08:15:20 +0000294#endif
295
Daniel Veillard05d987b2003-10-08 11:54:57 +0000296/**
297 * xmlIOErrMemory:
298 * @extra: extra informations
299 *
300 * Handle an out of memory condition
301 */
302static void
303xmlIOErrMemory(const char *extra)
304{
305 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
306}
307
308/**
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000309 * __xmlIOErr:
Daniel Veillard05d987b2003-10-08 11:54:57 +0000310 * @code: the error number
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000311 * @
Daniel Veillard05d987b2003-10-08 11:54:57 +0000312 * @extra: extra informations
313 *
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000314 * Handle an I/O error
Daniel Veillard05d987b2003-10-08 11:54:57 +0000315 */
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000316void
317__xmlIOErr(int domain, int code, const char *extra)
Daniel Veillard05d987b2003-10-08 11:54:57 +0000318{
319 unsigned int idx;
320
321 if (code == 0) {
322#ifdef HAVE_ERRNO_H
323 if (errno == 0) code = 0;
324#ifdef EACCES
325 else if (errno == EACCES) code = XML_IO_EACCES;
326#endif
327#ifdef EAGAIN
328 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
329#endif
330#ifdef EBADF
331 else if (errno == EBADF) code = XML_IO_EBADF;
332#endif
333#ifdef EBADMSG
334 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
335#endif
336#ifdef EBUSY
337 else if (errno == EBUSY) code = XML_IO_EBUSY;
338#endif
339#ifdef ECANCELED
340 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
341#endif
342#ifdef ECHILD
343 else if (errno == ECHILD) code = XML_IO_ECHILD;
344#endif
345#ifdef EDEADLK
346 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
347#endif
348#ifdef EDOM
349 else if (errno == EDOM) code = XML_IO_EDOM;
350#endif
351#ifdef EEXIST
352 else if (errno == EEXIST) code = XML_IO_EEXIST;
353#endif
354#ifdef EFAULT
355 else if (errno == EFAULT) code = XML_IO_EFAULT;
356#endif
357#ifdef EFBIG
358 else if (errno == EFBIG) code = XML_IO_EFBIG;
359#endif
360#ifdef EINPROGRESS
361 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
362#endif
363#ifdef EINTR
364 else if (errno == EINTR) code = XML_IO_EINTR;
365#endif
366#ifdef EINVAL
367 else if (errno == EINVAL) code = XML_IO_EINVAL;
368#endif
369#ifdef EIO
370 else if (errno == EIO) code = XML_IO_EIO;
371#endif
372#ifdef EISDIR
373 else if (errno == EISDIR) code = XML_IO_EISDIR;
374#endif
375#ifdef EMFILE
376 else if (errno == EMFILE) code = XML_IO_EMFILE;
377#endif
378#ifdef EMLINK
379 else if (errno == EMLINK) code = XML_IO_EMLINK;
380#endif
381#ifdef EMSGSIZE
382 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
383#endif
384#ifdef ENAMETOOLONG
385 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
386#endif
387#ifdef ENFILE
388 else if (errno == ENFILE) code = XML_IO_ENFILE;
389#endif
390#ifdef ENODEV
391 else if (errno == ENODEV) code = XML_IO_ENODEV;
392#endif
393#ifdef ENOENT
394 else if (errno == ENOENT) code = XML_IO_ENOENT;
395#endif
396#ifdef ENOEXEC
397 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
398#endif
399#ifdef ENOLCK
400 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
401#endif
402#ifdef ENOMEM
403 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
404#endif
405#ifdef ENOSPC
406 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
407#endif
408#ifdef ENOSYS
409 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
410#endif
411#ifdef ENOTDIR
412 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
413#endif
414#ifdef ENOTEMPTY
415 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
416#endif
417#ifdef ENOTSUP
418 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
419#endif
420#ifdef ENOTTY
421 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
422#endif
423#ifdef ENXIO
424 else if (errno == ENXIO) code = XML_IO_ENXIO;
425#endif
426#ifdef EPERM
427 else if (errno == EPERM) code = XML_IO_EPERM;
428#endif
429#ifdef EPIPE
430 else if (errno == EPIPE) code = XML_IO_EPIPE;
431#endif
432#ifdef ERANGE
433 else if (errno == ERANGE) code = XML_IO_ERANGE;
434#endif
435#ifdef EROFS
436 else if (errno == EROFS) code = XML_IO_EROFS;
437#endif
438#ifdef ESPIPE
439 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
440#endif
441#ifdef ESRCH
442 else if (errno == ESRCH) code = XML_IO_ESRCH;
443#endif
444#ifdef ETIMEDOUT
445 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
446#endif
447#ifdef EXDEV
448 else if (errno == EXDEV) code = XML_IO_EXDEV;
449#endif
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000450#ifdef ENOTSOCK
451 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
452#endif
453#ifdef EISCONN
454 else if (errno == EISCONN) code = XML_IO_EISCONN;
455#endif
456#ifdef ECONNREFUSED
457 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
458#endif
459#ifdef ETIMEDOUT
460 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
461#endif
462#ifdef ENETUNREACH
463 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
464#endif
465#ifdef EADDRINUSE
466 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
467#endif
468#ifdef EINPROGRESS
469 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
470#endif
471#ifdef EALREADY
472 else if (errno == EALREADY) code = XML_IO_EALREADY;
473#endif
474#ifdef EAFNOSUPPORT
475 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
476#endif
Daniel Veillard05d987b2003-10-08 11:54:57 +0000477 else code = XML_IO_UNKNOWN;
478#endif /* HAVE_ERRNO_H */
479 }
480 idx = 0;
481 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
482 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
483
Daniel Veillard2b0f8792003-10-10 19:36:36 +0000484 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
485}
486
487/**
488 * xmlIOErr:
489 * @code: the error number
490 * @extra: extra informations
491 *
492 * Handle an I/O error
493 */
494static void
495xmlIOErr(int code, const char *extra)
496{
497 __xmlIOErr(XML_FROM_IO, code, extra);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000498}
499
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000500/**
Daniel Veillarde8039df2003-10-27 11:25:13 +0000501 * __xmlLoaderErr:
502 * @ctx: the parser context
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000503 * @extra: extra informations
504 *
505 * Handle a resource access error
506 */
Daniel Veillarde8039df2003-10-27 11:25:13 +0000507void
508__xmlLoaderErr(void *ctx, const char *msg, const char *filename)
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000509{
Daniel Veillarde8039df2003-10-27 11:25:13 +0000510 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
Daniel Veillard659e71e2003-10-10 14:10:40 +0000511 xmlStructuredErrorFunc schannel = NULL;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000512 xmlGenericErrorFunc channel = NULL;
513 void *data = NULL;
514 xmlErrorLevel level = XML_ERR_ERROR;
515
Daniel Veillard157fee02003-10-31 10:36:03 +0000516 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
517 (ctxt->instate == XML_PARSER_EOF))
518 return;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000519 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
520 if (ctxt->validate) {
521 channel = ctxt->sax->error;
522 level = XML_ERR_ERROR;
523 } else {
524 channel = ctxt->sax->warning;
525 level = XML_ERR_WARNING;
526 }
Daniel Veillard5ea30d72004-11-08 11:54:28 +0000527 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
528 schannel = ctxt->sax->serror;
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000529 data = ctxt->userData;
530 }
Daniel Veillard659e71e2003-10-10 14:10:40 +0000531 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
Daniel Veillardcd6ff282003-10-08 22:38:13 +0000532 XML_IO_LOAD_ERROR, level, NULL, 0,
533 filename, NULL, NULL, 0, 0,
534 msg, filename);
535
536}
537
Daniel Veillard05d987b2003-10-08 11:54:57 +0000538/************************************************************************
539 * *
540 * Tree memory error handler *
541 * *
542 ************************************************************************/
Daniel Veillardf4862f02002-09-10 11:13:43 +0000543/**
Daniel Veillard01c13b52002-12-10 15:19:08 +0000544 * xmlNormalizeWindowsPath:
Daniel Veillard33300b42003-04-17 09:09:19 +0000545 * @path: the input file path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000546 *
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000547 * This function is obsolete. Please see xmlURIFromPath in uri.c for
548 * a better solution.
Daniel Veillard33300b42003-04-17 09:09:19 +0000549 *
550 * Returns a canonicalized version of the path
Daniel Veillardf4862f02002-09-10 11:13:43 +0000551 */
552xmlChar *
553xmlNormalizeWindowsPath(const xmlChar *path)
554{
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +0000555 return xmlCanonicPath(path);
Daniel Veillardf4862f02002-09-10 11:13:43 +0000556}
557
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000558/**
559 * xmlCleanupInputCallbacks:
560 *
561 * clears the entire input callback table. this includes the
562 * compiled-in I/O.
563 */
564void
565xmlCleanupInputCallbacks(void)
566{
567 int i;
568
569 if (!xmlInputCallbackInitialized)
570 return;
571
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000572 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000573 xmlInputCallbackTable[i].matchcallback = NULL;
574 xmlInputCallbackTable[i].opencallback = NULL;
575 xmlInputCallbackTable[i].readcallback = NULL;
576 xmlInputCallbackTable[i].closecallback = NULL;
577 }
578
579 xmlInputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000580 xmlInputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000581}
582
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000583/**
William M. Brack4e3a9fa2004-08-03 22:41:11 +0000584 * xmlPopInputCallbacks:
Daniel Veillardaecc0dc2004-05-08 02:32:07 +0000585 *
586 * Clear the top input callback from the input stack. this includes the
587 * compiled-in I/O.
588 *
589 * Returns the number of input callback registered or -1 in case of error.
590 */
591int
592xmlPopInputCallbacks(void)
593{
594 if (!xmlInputCallbackInitialized)
595 return(-1);
596
597 if (xmlInputCallbackNr <= 0)
598 return(-1);
599
600 xmlInputCallbackNr--;
601 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
602 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
603 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
604 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
605
606 return(xmlInputCallbackNr);
607}
608
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000609#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000610/**
611 * xmlCleanupOutputCallbacks:
612 *
613 * clears the entire output callback table. this includes the
614 * compiled-in I/O callbacks.
615 */
616void
617xmlCleanupOutputCallbacks(void)
618{
619 int i;
620
621 if (!xmlOutputCallbackInitialized)
622 return;
623
Daniel Veillard107ccaa2001-11-27 16:23:50 +0000624 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000625 xmlOutputCallbackTable[i].matchcallback = NULL;
626 xmlOutputCallbackTable[i].opencallback = NULL;
627 xmlOutputCallbackTable[i].writecallback = NULL;
628 xmlOutputCallbackTable[i].closecallback = NULL;
629 }
630
631 xmlOutputCallbackNr = 0;
Aleksey Sanin9c45ba82002-06-06 21:46:13 +0000632 xmlOutputCallbackInitialized = 0;
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000633}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000634#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardacf7ff02001-10-29 20:21:47 +0000635
Owen Taylor3473f882001-02-23 17:55:21 +0000636/************************************************************************
637 * *
638 * Standard I/O for file accesses *
639 * *
640 ************************************************************************/
641
642/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000643 * xmlCheckFilename:
Owen Taylor3473f882001-02-23 17:55:21 +0000644 * @path: the path to check
645 *
646 * function checks to see if @path is a valid source
647 * (file, socket...) for XML.
648 *
649 * if stat is not available on the target machine,
650 * returns 1. if stat fails, returns 0 (if calling
651 * stat on the filename fails, it can't be right).
652 * if stat succeeds and the file is a directory,
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000653 * returns 2. otherwise returns 1.
Owen Taylor3473f882001-02-23 17:55:21 +0000654 */
655
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000656int
Owen Taylor3473f882001-02-23 17:55:21 +0000657xmlCheckFilename (const char *path)
658{
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000659#if defined(HAVE_STAT) && !defined(WIN32)
Daniel Veillard0b309952006-05-02 20:34:38 +0000660 struct stat stat_buffer;
661#endif
Daniel Veillardf7416012006-04-27 08:15:20 +0000662 if (path == NULL)
Daniel Veillard0b309952006-05-02 20:34:38 +0000663 return(0);
Daniel Veillardf7416012006-04-27 08:15:20 +0000664
665#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
666 {
667 int retval = 0;
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000668
669 // One-time autodetect presence of _wstat. Not available for Win9x
670 static int (*winwstat)(const wchar_t *path,struct _stat *buffer) = INVALID_HANDLE_VALUE;
671
672 if (winwstat == INVALID_HANDLE_VALUE)
673 winwstat = (int (*)(const wchar_t *,struct _stat *))__xmlIOWin32GetWcharFunc("_wstat");
674
675 // Try utf-8 path first on systems capable
676 if (winwstat)
Daniel Veillardf7416012006-04-27 08:15:20 +0000677 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000678 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
679 if (wPath)
Daniel Veillardf7416012006-04-27 08:15:20 +0000680 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000681 struct _stat stat_buffer;
Daniel Veillardf7416012006-04-27 08:15:20 +0000682
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000683 if (winwstat(wPath,&stat_buffer) == 0)
684 {
685 retval = 1;
686
687 if (((stat_buffer.st_mode & S_IFDIR) == S_IFDIR))
688 retval = 2;
689 }
690
691 free(wPath);
Daniel Veillardf7416012006-04-27 08:15:20 +0000692 }
Daniel Veillardf7416012006-04-27 08:15:20 +0000693 }
694
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000695 // Fallback: Path in utf-8 representation not present or win9x
696 if ((winwstat == NULL) || (retval == 0))
697 {
698 struct _stat stat_buffer;
699
700 if (_stat(path,&stat_buffer) == 0)
701 {
702 retval = 1;
703
704 if (((stat_buffer.st_mode & S_IFDIR) == S_IFDIR))
705 retval = 2;
706 }
707 }
708
Daniel Veillardf7416012006-04-27 08:15:20 +0000709 return retval;
710 }
711#else
Owen Taylor3473f882001-02-23 17:55:21 +0000712#ifdef HAVE_STAT
Owen Taylor3473f882001-02-23 17:55:21 +0000713 if (stat(path, &stat_buffer) == -1)
714 return 0;
715
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000716#ifdef S_ISDIR
Daniel Veillardf7416012006-04-27 08:15:20 +0000717 if (S_ISDIR(stat_buffer.st_mode))
Daniel Veillard819d5cb2002-10-14 11:15:18 +0000718 return 2;
Daniel Veillardf7416012006-04-27 08:15:20 +0000719#endif /* S_ISDIR */
720#endif /* HAVE_STAT */
721#endif /* WIN32 */
Daniel Veillard34099b42004-11-04 17:34:35 +0000722
Owen Taylor3473f882001-02-23 17:55:21 +0000723 return 1;
724}
725
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000726static int
Owen Taylor3473f882001-02-23 17:55:21 +0000727xmlNop(void) {
728 return(0);
729}
730
731/**
Owen Taylor3473f882001-02-23 17:55:21 +0000732 * xmlFdRead:
733 * @context: the I/O context
734 * @buffer: where to drop data
735 * @len: number of bytes to read
736 *
737 * Read @len bytes to @buffer from the I/O channel.
738 *
739 * Returns the number of bytes written
740 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000741static int
Owen Taylor3473f882001-02-23 17:55:21 +0000742xmlFdRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000743 int ret;
744
745 ret = read((int) (long) context, &buffer[0], len);
746 if (ret < 0) xmlIOErr(0, "read()");
747 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000748}
749
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000750#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000751/**
752 * xmlFdWrite:
753 * @context: the I/O context
754 * @buffer: where to get data
755 * @len: number of bytes to write
756 *
757 * Write @len bytes from @buffer to the I/O channel.
758 *
759 * Returns the number of bytes written
760 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000761static int
Owen Taylor3473f882001-02-23 17:55:21 +0000762xmlFdWrite (void * context, const char * buffer, int len) {
Daniel Veillard9b693b42005-10-28 14:54:17 +0000763 int ret = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +0000764
Daniel Veillard9b693b42005-10-28 14:54:17 +0000765 if (len > 0) {
766 ret = write((int) (long) context, &buffer[0], len);
767 if (ret < 0) xmlIOErr(0, "write()");
768 }
Daniel Veillard05d987b2003-10-08 11:54:57 +0000769 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000770}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000771#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000772
773/**
774 * xmlFdClose:
775 * @context: the I/O context
776 *
777 * Close an I/O channel
Daniel Veillardf012a642001-07-23 19:10:52 +0000778 *
779 * Returns 0 in case of success and error code otherwise
Owen Taylor3473f882001-02-23 17:55:21 +0000780 */
Daniel Veillardf012a642001-07-23 19:10:52 +0000781static int
Owen Taylor3473f882001-02-23 17:55:21 +0000782xmlFdClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000783 int ret;
784 ret = close((int) (long) context);
785 if (ret < 0) xmlIOErr(0, "close()");
786 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000787}
788
789/**
790 * xmlFileMatch:
791 * @filename: the URI for matching
792 *
793 * input from FILE *
794 *
795 * Returns 1 if matches, 0 otherwise
796 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000797int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +0000798xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +0000799 return(1);
800}
801
802/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000803 * xmlFileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +0000804 * @filename: the URI for matching
805 *
806 * input from FILE *, supports compressed input
807 * if @filename is " " then the standard input is used
808 *
809 * Returns an I/O context or NULL in case of error
810 */
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000811static void *
812xmlFileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +0000813 const char *path = NULL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000814 FILE *fd = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000815
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000816 if (filename == NULL)
817 return(NULL);
818
Owen Taylor3473f882001-02-23 17:55:21 +0000819 if (!strcmp(filename, "-")) {
820 fd = stdin;
821 return((void *) fd);
822 }
823
Daniel Veillardf4862f02002-09-10 11:13:43 +0000824 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000825#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000826 path = &filename[17];
827#else
Owen Taylor3473f882001-02-23 17:55:21 +0000828 path = &filename[16];
Daniel Veillardb212bbb2002-08-25 14:39:16 +0000829#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000830 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000831#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000832 path = &filename[8];
833#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000834 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000835#endif
836 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000837 path = filename;
838
839 if (path == NULL)
840 return(NULL);
841 if (!xmlCheckFilename(path))
842 return(NULL);
843
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000844#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
Daniel Veillardf7416012006-04-27 08:15:20 +0000845 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000846 // One-time autodetect presence of _wfopen. Not available for Win9x
847 static FILE *(*winwfopen)(const wchar_t *path,const wchar_t *mode) = INVALID_HANDLE_VALUE;
848
849 if (winwfopen == INVALID_HANDLE_VALUE)
850 winwfopen = (FILE *(*)(const wchar_t *,const wchar_t *))__xmlIOWin32GetWcharFunc("_wfopen");
851
852 // Try to open file unicode path safe. If not available or win9x fall thru to non-unicode safe fopen()
853 if (winwfopen)
Daniel Veillardf7416012006-04-27 08:15:20 +0000854 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000855 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
856 if (wPath)
857 {
858 fd = winwfopen(wPath, L"rb");
859 free(wPath);
860 }
Daniel Veillardf7416012006-04-27 08:15:20 +0000861 }
Daniel Veillardf7416012006-04-27 08:15:20 +0000862 }
Owen Taylor3473f882001-02-23 17:55:21 +0000863#endif /* WIN32 */
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000864
865 if (fd == NULL)
866 fd = fopen(path, "r");
867 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000868 return((void *) fd);
869}
870
871/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000872 * xmlFileOpen:
873 * @filename: the URI for matching
874 *
875 * Wrapper around xmlFileOpen_real that try it with an unescaped
876 * version of @filename, if this fails fallback to @filename
Daniel Veillard71531f32003-02-05 13:19:53 +0000877 *
878 * Returns a handler or NULL in case or failure
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000879 */
880void *
881xmlFileOpen (const char *filename) {
882 char *unescaped;
883 void *retval;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000884
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000885 unescaped = xmlURIUnescapeString(filename, 0, NULL);
886 if (unescaped != NULL) {
887 retval = xmlFileOpen_real(unescaped);
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +0000888 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000889 } else {
890 retval = xmlFileOpen_real(filename);
891 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000892 return retval;
893}
894
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000895#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +0000896/**
Owen Taylor3473f882001-02-23 17:55:21 +0000897 * xmlFileOpenW:
898 * @filename: the URI for matching
899 *
900 * output to from FILE *,
901 * if @filename is "-" then the standard output is used
902 *
903 * Returns an I/O context or NULL in case of error
904 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000905static void *
Owen Taylor3473f882001-02-23 17:55:21 +0000906xmlFileOpenW (const char *filename) {
907 const char *path = NULL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000908 FILE *fd = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000909
910 if (!strcmp(filename, "-")) {
911 fd = stdout;
912 return((void *) fd);
913 }
914
Daniel Veillardf4862f02002-09-10 11:13:43 +0000915 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000916#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +0000917 path = &filename[17];
918#else
Owen Taylor3473f882001-02-23 17:55:21 +0000919 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +0000920#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000921 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +0000922#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +0000923 path = &filename[8];
924#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +0000925 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +0000926#endif
927 } else
Owen Taylor3473f882001-02-23 17:55:21 +0000928 path = filename;
929
930 if (path == NULL)
931 return(NULL);
932
Daniel Veillardf7416012006-04-27 08:15:20 +0000933#if defined(WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
934 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000935 // One-time autodetect presence of _wfopen. Not available for Win9x
936 static FILE *(*winwfopen)(const wchar_t *path,const wchar_t *mode) = INVALID_HANDLE_VALUE;
937
938 if (winwfopen == INVALID_HANDLE_VALUE)
939 winwfopen = (FILE *(*)(const wchar_t *,const wchar_t *))__xmlIOWin32GetWcharFunc("_wfopen");
940
941 // Try to open file unicode path safe. If not available or win9x fall thru to non-unicode safe fopen()
942 if (winwfopen)
Daniel Veillardf7416012006-04-27 08:15:20 +0000943 {
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000944 wchar_t *wPath = __xmlIOWin32UTF8ToWChar(path);
945 if (wPath)
946 {
947 fd = winwfopen(wPath, L"wb");
948 free(wPath);
949 }
950 }
Daniel Veillardf7416012006-04-27 08:15:20 +0000951 }
Daniel Veillardf7416012006-04-27 08:15:20 +0000952#endif /* WIN32 */
953
Daniel Veillarde5a3f372006-08-30 13:11:36 +0000954 if (fd == NULL)
955 fd = fopen(path, "wb");
956
Daniel Veillardf7416012006-04-27 08:15:20 +0000957 if (fd == NULL) xmlIOErr(0, path);
Owen Taylor3473f882001-02-23 17:55:21 +0000958 return((void *) fd);
959}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000960#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +0000961
962/**
963 * xmlFileRead:
964 * @context: the I/O context
965 * @buffer: where to drop data
966 * @len: number of bytes to write
967 *
968 * Read @len bytes to @buffer from the I/O channel.
969 *
Daniel Veillardce682bc2004-11-05 17:22:25 +0000970 * Returns the number of bytes written or < 0 in case of failure
Owen Taylor3473f882001-02-23 17:55:21 +0000971 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +0000972int
Owen Taylor3473f882001-02-23 17:55:21 +0000973xmlFileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +0000974 int ret;
Daniel Veillardce682bc2004-11-05 17:22:25 +0000975 if ((context == NULL) || (buffer == NULL))
976 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +0000977 ret = fread(&buffer[0], 1, len, (FILE *) context);
978 if (ret < 0) xmlIOErr(0, "fread()");
979 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000980}
981
Daniel Veillarda9cce9c2003-09-29 13:20:24 +0000982#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +0000983/**
984 * xmlFileWrite:
985 * @context: the I/O context
986 * @buffer: where to drop data
987 * @len: number of bytes to write
988 *
989 * Write @len bytes from @buffer to the I/O channel.
990 *
991 * Returns the number of bytes written
992 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000993static int
Owen Taylor3473f882001-02-23 17:55:21 +0000994xmlFileWrite (void * context, const char * buffer, int len) {
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000995 int items;
996
Daniel Veillardce682bc2004-11-05 17:22:25 +0000997 if ((context == NULL) || (buffer == NULL))
998 return(-1);
Daniel Veillard4a6d39b2002-12-17 18:33:01 +0000999 items = fwrite(&buffer[0], len, 1, (FILE *) context);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001000 if ((items == 0) && (ferror((FILE *) context))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001001 xmlIOErr(0, "fwrite()");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00001002 return(-1);
1003 }
Daniel Veillard4a6d39b2002-12-17 18:33:01 +00001004 return(items * len);
Owen Taylor3473f882001-02-23 17:55:21 +00001005}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001006#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001007
1008/**
1009 * xmlFileClose:
1010 * @context: the I/O context
1011 *
1012 * Close an I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001013 *
1014 * Returns 0 or -1 in case of error
Owen Taylor3473f882001-02-23 17:55:21 +00001015 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001016int
Owen Taylor3473f882001-02-23 17:55:21 +00001017xmlFileClose (void * context) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001018 FILE *fil;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001019 int ret;
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001020
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001021 if (context == NULL)
1022 return(-1);
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001023 fil = (FILE *) context;
Daniel Veillard500a1de2004-03-22 15:22:58 +00001024 if ((fil == stdout) || (fil == stderr)) {
1025 ret = fflush(fil);
1026 if (ret < 0)
1027 xmlIOErr(0, "fflush()");
1028 return(0);
1029 }
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001030 if (fil == stdin)
1031 return(0);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001032 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1033 if (ret < 0)
1034 xmlIOErr(0, "fclose()");
1035 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001036}
1037
1038/**
1039 * xmlFileFlush:
1040 * @context: the I/O context
1041 *
1042 * Flush an I/O channel
1043 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001044static int
Owen Taylor3473f882001-02-23 17:55:21 +00001045xmlFileFlush (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001046 int ret;
Daniel Veillardb1b3a3e2004-11-03 23:25:47 +00001047
1048 if (context == NULL)
1049 return(-1);
Daniel Veillard05d987b2003-10-08 11:54:57 +00001050 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1051 if (ret < 0)
1052 xmlIOErr(0, "fflush()");
1053 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001054}
1055
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001056#ifdef LIBXML_OUTPUT_ENABLED
1057/**
1058 * xmlBufferWrite:
1059 * @context: the xmlBuffer
1060 * @buffer: the data to write
1061 * @len: number of bytes to write
1062 *
1063 * Write @len bytes from @buffer to the xml buffer
1064 *
1065 * Returns the number of bytes written
1066 */
1067static int
1068xmlBufferWrite (void * context, const char * buffer, int len) {
1069 int ret;
1070
1071 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1072 if (ret != 0)
1073 return(-1);
1074 return(len);
1075}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00001076#endif
1077
Owen Taylor3473f882001-02-23 17:55:21 +00001078#ifdef HAVE_ZLIB_H
1079/************************************************************************
1080 * *
1081 * I/O for compressed file accesses *
1082 * *
1083 ************************************************************************/
1084/**
1085 * xmlGzfileMatch:
1086 * @filename: the URI for matching
1087 *
1088 * input from compressed file test
1089 *
1090 * Returns 1 if matches, 0 otherwise
1091 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001092static int
Daniel Veillardc86a4fa2001-03-26 16:28:29 +00001093xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00001094 return(1);
1095}
1096
1097/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001098 * xmlGzfileOpen_real:
Owen Taylor3473f882001-02-23 17:55:21 +00001099 * @filename: the URI for matching
1100 *
1101 * input from compressed file open
1102 * if @filename is " " then the standard input is used
1103 *
1104 * Returns an I/O context or NULL in case of error
1105 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001106static void *
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001107xmlGzfileOpen_real (const char *filename) {
Owen Taylor3473f882001-02-23 17:55:21 +00001108 const char *path = NULL;
1109 gzFile fd;
1110
1111 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001112 fd = gzdopen(dup(0), "rb");
Owen Taylor3473f882001-02-23 17:55:21 +00001113 return((void *) fd);
1114 }
1115
Daniel Veillardf4862f02002-09-10 11:13:43 +00001116 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001117#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001118 path = &filename[17];
1119#else
Owen Taylor3473f882001-02-23 17:55:21 +00001120 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001121#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001122 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001123#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001124 path = &filename[8];
1125#else
Owen Taylor3473f882001-02-23 17:55:21 +00001126 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001127#endif
1128 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001129 path = filename;
1130
1131 if (path == NULL)
1132 return(NULL);
1133 if (!xmlCheckFilename(path))
1134 return(NULL);
1135
1136 fd = gzopen(path, "rb");
1137 return((void *) fd);
1138}
1139
1140/**
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001141 * xmlGzfileOpen:
1142 * @filename: the URI for matching
1143 *
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001144 * Wrapper around xmlGzfileOpen if the open fais, it will
1145 * try to unescape @filename
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001146 */
1147static void *
1148xmlGzfileOpen (const char *filename) {
1149 char *unescaped;
1150 void *retval;
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00001151
1152 retval = xmlGzfileOpen_real(filename);
1153 if (retval == NULL) {
1154 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1155 if (unescaped != NULL) {
1156 retval = xmlGzfileOpen_real(unescaped);
1157 }
1158 xmlFree(unescaped);
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001159 }
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001160 return retval;
1161}
1162
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001163#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardcacbe5d2003-01-10 16:09:51 +00001164/**
Owen Taylor3473f882001-02-23 17:55:21 +00001165 * xmlGzfileOpenW:
1166 * @filename: the URI for matching
1167 * @compression: the compression factor (0 - 9 included)
1168 *
1169 * input from compressed file open
1170 * if @filename is " " then the standard input is used
1171 *
1172 * Returns an I/O context or NULL in case of error
1173 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001174static void *
Owen Taylor3473f882001-02-23 17:55:21 +00001175xmlGzfileOpenW (const char *filename, int compression) {
1176 const char *path = NULL;
1177 char mode[15];
1178 gzFile fd;
1179
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001180 snprintf(mode, sizeof(mode), "wb%d", compression);
Owen Taylor3473f882001-02-23 17:55:21 +00001181 if (!strcmp(filename, "-")) {
Daniel Veillarda9e65e82001-10-30 10:32:36 +00001182 fd = gzdopen(dup(1), mode);
Owen Taylor3473f882001-02-23 17:55:21 +00001183 return((void *) fd);
1184 }
1185
Daniel Veillardf4862f02002-09-10 11:13:43 +00001186 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001187#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00001188 path = &filename[17];
1189#else
Owen Taylor3473f882001-02-23 17:55:21 +00001190 path = &filename[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00001191#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001192 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00001193#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardfe703322001-08-14 12:18:09 +00001194 path = &filename[8];
1195#else
Daniel Veillard3c2758d2001-05-31 18:43:43 +00001196 path = &filename[7];
Daniel Veillardfe703322001-08-14 12:18:09 +00001197#endif
1198 } else
Owen Taylor3473f882001-02-23 17:55:21 +00001199 path = filename;
1200
1201 if (path == NULL)
1202 return(NULL);
1203
1204 fd = gzopen(path, mode);
1205 return((void *) fd);
1206}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001207#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001208
1209/**
1210 * xmlGzfileRead:
1211 * @context: the I/O context
1212 * @buffer: where to drop data
1213 * @len: number of bytes to write
1214 *
1215 * Read @len bytes to @buffer from the compressed I/O channel.
1216 *
1217 * Returns the number of bytes written
1218 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001219static int
Owen Taylor3473f882001-02-23 17:55:21 +00001220xmlGzfileRead (void * context, char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001221 int ret;
1222
1223 ret = gzread((gzFile) context, &buffer[0], len);
1224 if (ret < 0) xmlIOErr(0, "gzread()");
1225 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001226}
1227
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001228#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001229/**
1230 * xmlGzfileWrite:
1231 * @context: the I/O context
1232 * @buffer: where to drop data
1233 * @len: number of bytes to write
1234 *
1235 * Write @len bytes from @buffer to the compressed I/O channel.
1236 *
1237 * Returns the number of bytes written
1238 */
Daniel Veillard56a4cb82001-03-24 17:00:36 +00001239static int
Owen Taylor3473f882001-02-23 17:55:21 +00001240xmlGzfileWrite (void * context, const char * buffer, int len) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001241 int ret;
1242
1243 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1244 if (ret < 0) xmlIOErr(0, "gzwrite()");
1245 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001246}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001247#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00001248
1249/**
1250 * xmlGzfileClose:
1251 * @context: the I/O context
1252 *
1253 * Close a compressed I/O channel
1254 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001255static int
Owen Taylor3473f882001-02-23 17:55:21 +00001256xmlGzfileClose (void * context) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001257 int ret;
1258
1259 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1260 if (ret < 0) xmlIOErr(0, "gzclose()");
1261 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +00001262}
1263#endif /* HAVE_ZLIB_H */
1264
1265#ifdef LIBXML_HTTP_ENABLED
1266/************************************************************************
1267 * *
1268 * I/O for HTTP file accesses *
1269 * *
1270 ************************************************************************/
Daniel Veillardf012a642001-07-23 19:10:52 +00001271
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001272#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001273typedef struct xmlIOHTTPWriteCtxt_
1274{
1275 int compression;
1276
1277 char * uri;
1278
1279 void * doc_buff;
1280
1281} xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1282
1283#ifdef HAVE_ZLIB_H
1284
1285#define DFLT_WBITS ( -15 )
1286#define DFLT_MEM_LVL ( 8 )
1287#define GZ_MAGIC1 ( 0x1f )
1288#define GZ_MAGIC2 ( 0x8b )
1289#define LXML_ZLIB_OS_CODE ( 0x03 )
1290#define INIT_HTTP_BUFF_SIZE ( 32768 )
1291#define DFLT_ZLIB_RATIO ( 5 )
1292
1293/*
1294** Data structure and functions to work with sending compressed data
1295** via HTTP.
1296*/
1297
1298typedef struct xmlZMemBuff_
1299{
1300 unsigned long size;
1301 unsigned long crc;
1302
1303 unsigned char * zbuff;
1304 z_stream zctrl;
1305
1306} xmlZMemBuff, *xmlZMemBuffPtr;
1307
1308/**
1309 * append_reverse_ulong
1310 * @buff: Compressed memory buffer
1311 * @data: Unsigned long to append
1312 *
1313 * Append a unsigned long in reverse byte order to the end of the
1314 * memory buffer.
1315 */
1316static void
1317append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1318
1319 int idx;
1320
1321 if ( buff == NULL )
1322 return;
1323
1324 /*
1325 ** This is plagiarized from putLong in gzio.c (zlib source) where
1326 ** the number "4" is hardcoded. If zlib is ever patched to
1327 ** support 64 bit file sizes, this code would need to be patched
1328 ** as well.
1329 */
1330
1331 for ( idx = 0; idx < 4; idx++ ) {
1332 *buff->zctrl.next_out = ( data & 0xff );
1333 data >>= 8;
1334 buff->zctrl.next_out++;
1335 }
1336
1337 return;
1338}
1339
1340/**
1341 *
1342 * xmlFreeZMemBuff
1343 * @buff: The memory buffer context to clear
1344 *
1345 * Release all the resources associated with the compressed memory buffer.
1346 */
1347static void
1348xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
William M. Brack78637da2003-07-31 14:47:38 +00001349
1350#ifdef DEBUG_HTTP
Daniel Veillardf012a642001-07-23 19:10:52 +00001351 int z_err;
William M. Brack78637da2003-07-31 14:47:38 +00001352#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001353
1354 if ( buff == NULL )
1355 return;
1356
1357 xmlFree( buff->zbuff );
Daniel Veillardf012a642001-07-23 19:10:52 +00001358#ifdef DEBUG_HTTP
William M. Brack78637da2003-07-31 14:47:38 +00001359 z_err = deflateEnd( &buff->zctrl );
Daniel Veillardf012a642001-07-23 19:10:52 +00001360 if ( z_err != Z_OK )
1361 xmlGenericError( xmlGenericErrorContext,
1362 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1363 z_err );
William M. Brack78637da2003-07-31 14:47:38 +00001364#else
1365 deflateEnd( &buff->zctrl );
William M. Brack779af002003-08-01 15:55:39 +00001366#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00001367
1368 xmlFree( buff );
1369 return;
1370}
1371
1372/**
1373 * xmlCreateZMemBuff
1374 *@compression: Compression value to use
1375 *
1376 * Create a memory buffer to hold the compressed XML document. The
1377 * compressed document in memory will end up being identical to what
1378 * would be created if gzopen/gzwrite/gzclose were being used to
1379 * write the document to disk. The code for the header/trailer data to
1380 * the compression is plagiarized from the zlib source files.
1381 */
1382static void *
1383xmlCreateZMemBuff( int compression ) {
1384
1385 int z_err;
1386 int hdr_lgth;
1387 xmlZMemBuffPtr buff = NULL;
1388
1389 if ( ( compression < 1 ) || ( compression > 9 ) )
1390 return ( NULL );
1391
1392 /* Create the control and data areas */
1393
1394 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1395 if ( buff == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001396 xmlIOErrMemory("creating buffer context");
Daniel Veillardf012a642001-07-23 19:10:52 +00001397 return ( NULL );
1398 }
1399
1400 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1401 buff->size = INIT_HTTP_BUFF_SIZE;
1402 buff->zbuff = xmlMalloc( buff->size );
1403 if ( buff->zbuff == NULL ) {
1404 xmlFreeZMemBuff( buff );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001405 xmlIOErrMemory("creating buffer");
Daniel Veillardf012a642001-07-23 19:10:52 +00001406 return ( NULL );
1407 }
1408
1409 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1410 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1411 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001412 xmlChar msg[500];
Daniel Veillardf012a642001-07-23 19:10:52 +00001413 xmlFreeZMemBuff( buff );
1414 buff = NULL;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001415 xmlStrPrintf(msg, 500,
1416 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1417 "Error initializing compression context. ZLIB error:",
1418 z_err );
1419 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001420 return ( NULL );
1421 }
1422
1423 /* Set the header data. The CRC will be needed for the trailer */
Daniel Veillard24505b02005-07-28 23:49:35 +00001424 buff->crc = crc32( 0L, NULL, 0 );
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001425 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1426 "%c%c%c%c%c%c%c%c%c%c",
Daniel Veillardf012a642001-07-23 19:10:52 +00001427 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1428 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1429 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1430 buff->zctrl.avail_out = buff->size - hdr_lgth;
1431
1432 return ( buff );
1433}
1434
1435/**
1436 * xmlZMemBuffExtend
1437 * @buff: Buffer used to compress and consolidate data.
1438 * @ext_amt: Number of bytes to extend the buffer.
1439 *
1440 * Extend the internal buffer used to store the compressed data by the
1441 * specified amount.
1442 *
1443 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1444 * the original buffer still exists at the original size.
1445 */
1446static int
1447xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1448
1449 int rc = -1;
1450 size_t new_size;
1451 size_t cur_used;
1452
1453 unsigned char * tmp_ptr = NULL;
1454
1455 if ( buff == NULL )
1456 return ( -1 );
1457
1458 else if ( ext_amt == 0 )
1459 return ( 0 );
1460
1461 cur_used = buff->zctrl.next_out - buff->zbuff;
1462 new_size = buff->size + ext_amt;
1463
1464#ifdef DEBUG_HTTP
1465 if ( cur_used > new_size )
1466 xmlGenericError( xmlGenericErrorContext,
1467 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1468 "Buffer overwrite detected during compressed memory",
1469 "buffer extension. Overflowed by",
1470 (cur_used - new_size ) );
1471#endif
1472
1473 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1474 if ( tmp_ptr != NULL ) {
1475 rc = 0;
1476 buff->size = new_size;
1477 buff->zbuff = tmp_ptr;
1478 buff->zctrl.next_out = tmp_ptr + cur_used;
1479 buff->zctrl.avail_out = new_size - cur_used;
1480 }
1481 else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001482 xmlChar msg[500];
1483 xmlStrPrintf(msg, 500,
1484 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1485 "Allocation failure extending output buffer to",
1486 new_size );
1487 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001488 }
1489
1490 return ( rc );
1491}
1492
1493/**
1494 * xmlZMemBuffAppend
1495 * @buff: Buffer used to compress and consolidate data
1496 * @src: Uncompressed source content to append to buffer
1497 * @len: Length of source data to append to buffer
1498 *
1499 * Compress and append data to the internal buffer. The data buffer
1500 * will be expanded if needed to store the additional data.
1501 *
1502 * Returns the number of bytes appended to the buffer or -1 on error.
1503 */
1504static int
1505xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1506
1507 int z_err;
1508 size_t min_accept;
1509
1510 if ( ( buff == NULL ) || ( src == NULL ) )
1511 return ( -1 );
1512
1513 buff->zctrl.avail_in = len;
1514 buff->zctrl.next_in = (unsigned char *)src;
1515 while ( buff->zctrl.avail_in > 0 ) {
1516 /*
1517 ** Extend the buffer prior to deflate call if a reasonable amount
1518 ** of output buffer space is not available.
1519 */
1520 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1521 if ( buff->zctrl.avail_out <= min_accept ) {
1522 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1523 return ( -1 );
1524 }
1525
1526 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1527 if ( z_err != Z_OK ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001528 xmlChar msg[500];
1529 xmlStrPrintf(msg, 500,
1530 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
Daniel Veillardf012a642001-07-23 19:10:52 +00001531 "Compression error while appending",
1532 len, "bytes to buffer. ZLIB error", z_err );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001533 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001534 return ( -1 );
1535 }
1536 }
1537
1538 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1539
1540 return ( len );
1541}
1542
1543/**
1544 * xmlZMemBuffGetContent
1545 * @buff: Compressed memory content buffer
1546 * @data_ref: Pointer reference to point to compressed content
1547 *
1548 * Flushes the compression buffers, appends gzip file trailers and
1549 * returns the compressed content and length of the compressed data.
1550 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1551 *
1552 * Returns the length of the compressed data or -1 on error.
1553 */
1554static int
1555xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1556
1557 int zlgth = -1;
1558 int z_err;
1559
1560 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1561 return ( -1 );
1562
1563 /* Need to loop until compression output buffers are flushed */
1564
1565 do
1566 {
1567 z_err = deflate( &buff->zctrl, Z_FINISH );
1568 if ( z_err == Z_OK ) {
1569 /* In this case Z_OK means more buffer space needed */
1570
1571 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1572 return ( -1 );
1573 }
1574 }
1575 while ( z_err == Z_OK );
1576
1577 /* If the compression state is not Z_STREAM_END, some error occurred */
1578
1579 if ( z_err == Z_STREAM_END ) {
1580
1581 /* Need to append the gzip data trailer */
1582
1583 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1584 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1585 return ( -1 );
1586 }
1587
1588 /*
1589 ** For whatever reason, the CRC and length data are pushed out
1590 ** in reverse byte order. So a memcpy can't be used here.
1591 */
1592
1593 append_reverse_ulong( buff, buff->crc );
1594 append_reverse_ulong( buff, buff->zctrl.total_in );
1595
1596 zlgth = buff->zctrl.next_out - buff->zbuff;
1597 *data_ref = (char *)buff->zbuff;
1598 }
1599
Daniel Veillard05d987b2003-10-08 11:54:57 +00001600 else {
1601 xmlChar msg[500];
1602 xmlStrPrintf(msg, 500,
1603 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1604 "Error flushing zlib buffers. Error code", z_err );
1605 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1606 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001607
1608 return ( zlgth );
1609}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001610#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001611#endif /* HAVE_ZLIB_H */
1612
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001613#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001614/**
1615 * xmlFreeHTTPWriteCtxt
1616 * @ctxt: Context to cleanup
1617 *
1618 * Free allocated memory and reclaim system resources.
1619 *
1620 * No return value.
1621 */
1622static void
1623xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1624{
1625 if ( ctxt->uri != NULL )
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001626 xmlFree( ctxt->uri );
Daniel Veillardf012a642001-07-23 19:10:52 +00001627
1628 if ( ctxt->doc_buff != NULL ) {
1629
1630#ifdef HAVE_ZLIB_H
1631 if ( ctxt->compression > 0 ) {
1632 xmlFreeZMemBuff( ctxt->doc_buff );
1633 }
1634 else
1635#endif
1636 {
1637 xmlOutputBufferClose( ctxt->doc_buff );
1638 }
1639 }
1640
Daniel Veillard819d5cb2002-10-14 11:15:18 +00001641 xmlFree( ctxt );
Daniel Veillardf012a642001-07-23 19:10:52 +00001642 return;
1643}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001644#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001645
1646
Owen Taylor3473f882001-02-23 17:55:21 +00001647/**
1648 * xmlIOHTTPMatch:
1649 * @filename: the URI for matching
1650 *
1651 * check if the URI matches an HTTP one
1652 *
1653 * Returns 1 if matches, 0 otherwise
1654 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001655int
Owen Taylor3473f882001-02-23 17:55:21 +00001656xmlIOHTTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001657 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
Owen Taylor3473f882001-02-23 17:55:21 +00001658 return(1);
1659 return(0);
1660}
1661
1662/**
1663 * xmlIOHTTPOpen:
1664 * @filename: the URI for matching
1665 *
1666 * open an HTTP I/O channel
1667 *
1668 * Returns an I/O context or NULL in case of error
1669 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001670void *
Owen Taylor3473f882001-02-23 17:55:21 +00001671xmlIOHTTPOpen (const char *filename) {
1672 return(xmlNanoHTTPOpen(filename, NULL));
1673}
1674
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001675#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001676/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001677 * xmlIOHTTPOpenW:
Daniel Veillardf012a642001-07-23 19:10:52 +00001678 * @post_uri: The destination URI for the document
1679 * @compression: The compression desired for the document.
1680 *
1681 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1682 * request. Non-static as is called from the output buffer creation routine.
1683 *
1684 * Returns an I/O context or NULL in case of error.
1685 */
1686
1687void *
Daniel Veillard572577e2002-01-18 16:23:55 +00001688xmlIOHTTPOpenW(const char *post_uri, int compression)
1689{
Daniel Veillardf012a642001-07-23 19:10:52 +00001690
Daniel Veillard572577e2002-01-18 16:23:55 +00001691 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001692
Daniel Veillard572577e2002-01-18 16:23:55 +00001693 if (post_uri == NULL)
1694 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001695
Daniel Veillard572577e2002-01-18 16:23:55 +00001696 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1697 if (ctxt == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001698 xmlIOErrMemory("creating HTTP output context");
Daniel Veillard572577e2002-01-18 16:23:55 +00001699 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001700 }
1701
Daniel Veillard572577e2002-01-18 16:23:55 +00001702 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
Daniel Veillardf012a642001-07-23 19:10:52 +00001703
Daniel Veillard572577e2002-01-18 16:23:55 +00001704 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1705 if (ctxt->uri == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001706 xmlIOErrMemory("copying URI");
Daniel Veillard572577e2002-01-18 16:23:55 +00001707 xmlFreeHTTPWriteCtxt(ctxt);
1708 return (NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001709 }
1710
1711 /*
Daniel Veillard572577e2002-01-18 16:23:55 +00001712 * ** Since the document length is required for an HTTP post,
1713 * ** need to put the document into a buffer. A memory buffer
1714 * ** is being used to avoid pushing the data to disk and back.
1715 */
Daniel Veillardf012a642001-07-23 19:10:52 +00001716
1717#ifdef HAVE_ZLIB_H
Daniel Veillard572577e2002-01-18 16:23:55 +00001718 if ((compression > 0) && (compression <= 9)) {
1719
1720 ctxt->compression = compression;
1721 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1722 } else
Daniel Veillardf012a642001-07-23 19:10:52 +00001723#endif
1724 {
Daniel Veillard572577e2002-01-18 16:23:55 +00001725 /* Any character conversions should have been done before this */
Daniel Veillardf012a642001-07-23 19:10:52 +00001726
Daniel Veillard572577e2002-01-18 16:23:55 +00001727 ctxt->doc_buff = xmlAllocOutputBuffer(NULL);
Daniel Veillardf012a642001-07-23 19:10:52 +00001728 }
1729
Daniel Veillard572577e2002-01-18 16:23:55 +00001730 if (ctxt->doc_buff == NULL) {
1731 xmlFreeHTTPWriteCtxt(ctxt);
1732 ctxt = NULL;
Daniel Veillardf012a642001-07-23 19:10:52 +00001733 }
1734
Daniel Veillard572577e2002-01-18 16:23:55 +00001735 return (ctxt);
Daniel Veillardf012a642001-07-23 19:10:52 +00001736}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001737#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001738
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001739#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001740/**
1741 * xmlIOHTTPDfltOpenW
1742 * @post_uri: The destination URI for this document.
1743 *
1744 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1745 * HTTP post command. This function should generally not be used as
1746 * the open callback is short circuited in xmlOutputBufferCreateFile.
1747 *
1748 * Returns a pointer to the new IO context.
1749 */
1750static void *
1751xmlIOHTTPDfltOpenW( const char * post_uri ) {
1752 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1753}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001754#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001755
1756/**
Owen Taylor3473f882001-02-23 17:55:21 +00001757 * xmlIOHTTPRead:
1758 * @context: the I/O context
1759 * @buffer: where to drop data
1760 * @len: number of bytes to write
1761 *
1762 * Read @len bytes to @buffer from the I/O channel.
1763 *
1764 * Returns the number of bytes written
1765 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001766int
Owen Taylor3473f882001-02-23 17:55:21 +00001767xmlIOHTTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00001768 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00001769 return(xmlNanoHTTPRead(context, &buffer[0], len));
1770}
1771
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001772#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00001773/**
Daniel Veillardf012a642001-07-23 19:10:52 +00001774 * xmlIOHTTPWrite
1775 * @context: previously opened writing context
1776 * @buffer: data to output to temporary buffer
1777 * @len: bytes to output
1778 *
1779 * Collect data from memory buffer into a temporary file for later
1780 * processing.
1781 *
1782 * Returns number of bytes written.
1783 */
1784
1785static int
1786xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1787
1788 xmlIOHTTPWriteCtxtPtr ctxt = context;
1789
1790 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1791 return ( -1 );
1792
1793 if ( len > 0 ) {
1794
1795 /* Use gzwrite or fwrite as previously setup in the open call */
1796
1797#ifdef HAVE_ZLIB_H
1798 if ( ctxt->compression > 0 )
1799 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1800
1801 else
1802#endif
1803 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1804
1805 if ( len < 0 ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001806 xmlChar msg[500];
1807 xmlStrPrintf(msg, 500,
1808 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001809 "Error appending to internal buffer.",
1810 "Error sending document to URI",
1811 ctxt->uri );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001812 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001813 }
1814 }
1815
1816 return ( len );
1817}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001818#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001819
1820
1821/**
Owen Taylor3473f882001-02-23 17:55:21 +00001822 * xmlIOHTTPClose:
1823 * @context: the I/O context
1824 *
1825 * Close an HTTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00001826 *
1827 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00001828 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00001829int
Owen Taylor3473f882001-02-23 17:55:21 +00001830xmlIOHTTPClose (void * context) {
1831 xmlNanoHTTPClose(context);
Daniel Veillardf012a642001-07-23 19:10:52 +00001832 return 0;
Owen Taylor3473f882001-02-23 17:55:21 +00001833}
Daniel Veillardf012a642001-07-23 19:10:52 +00001834
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001835#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillardf012a642001-07-23 19:10:52 +00001836/**
1837 * xmlIOHTTCloseWrite
1838 * @context: The I/O context
1839 * @http_mthd: The HTTP method to be used when sending the data
1840 *
1841 * Close the transmit HTTP I/O channel and actually send the data.
1842 */
1843static int
1844xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1845
1846 int close_rc = -1;
1847 int http_rtn = 0;
1848 int content_lgth = 0;
1849 xmlIOHTTPWriteCtxtPtr ctxt = context;
1850
1851 char * http_content = NULL;
1852 char * content_encoding = NULL;
1853 char * content_type = (char *) "text/xml";
1854 void * http_ctxt = NULL;
1855
1856 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1857 return ( -1 );
1858
1859 /* Retrieve the content from the appropriate buffer */
1860
1861#ifdef HAVE_ZLIB_H
1862
1863 if ( ctxt->compression > 0 ) {
1864 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
1865 content_encoding = (char *) "Content-Encoding: gzip";
1866 }
1867 else
1868#endif
1869 {
1870 /* Pull the data out of the memory output buffer */
1871
1872 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
1873 http_content = (char *)dctxt->buffer->content;
1874 content_lgth = dctxt->buffer->use;
1875 }
1876
1877 if ( http_content == NULL ) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00001878 xmlChar msg[500];
1879 xmlStrPrintf(msg, 500,
1880 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
1881 "Error retrieving content.\nUnable to",
1882 http_mthd, "data to URI", ctxt->uri );
1883 xmlIOErr(XML_IO_WRITE, (const char *) msg);
Daniel Veillardf012a642001-07-23 19:10:52 +00001884 }
1885
1886 else {
1887
1888 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1889 &content_type, content_encoding,
1890 content_lgth );
1891
1892 if ( http_ctxt != NULL ) {
1893#ifdef DEBUG_HTTP
1894 /* If testing/debugging - dump reply with request content */
1895
1896 FILE * tst_file = NULL;
1897 char buffer[ 4096 ];
1898 char * dump_name = NULL;
1899 int avail;
1900
1901 xmlGenericError( xmlGenericErrorContext,
1902 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
1903 http_mthd, ctxt->uri,
1904 xmlNanoHTTPReturnCode( http_ctxt ) );
1905
1906 /*
1907 ** Since either content or reply may be gzipped,
1908 ** dump them to separate files instead of the
1909 ** standard error context.
1910 */
1911
1912 dump_name = tempnam( NULL, "lxml" );
1913 if ( dump_name != NULL ) {
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001914 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
Daniel Veillardf012a642001-07-23 19:10:52 +00001915
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001916 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001917 if ( tst_file != NULL ) {
1918 xmlGenericError( xmlGenericErrorContext,
1919 "Transmitted content saved in file: %s\n", buffer );
1920
1921 fwrite( http_content, sizeof( char ),
1922 content_lgth, tst_file );
1923 fclose( tst_file );
1924 }
1925
Aleksey Sanin49cc9752002-06-14 17:07:10 +00001926 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
Daniel Veillardcbbd78d2003-07-20 15:21:30 +00001927 tst_file = fopen( buffer, "wb" );
Daniel Veillardf012a642001-07-23 19:10:52 +00001928 if ( tst_file != NULL ) {
1929 xmlGenericError( xmlGenericErrorContext,
1930 "Reply content saved in file: %s\n", buffer );
1931
1932
1933 while ( (avail = xmlNanoHTTPRead( http_ctxt,
1934 buffer, sizeof( buffer ) )) > 0 ) {
1935
1936 fwrite( buffer, sizeof( char ), avail, tst_file );
1937 }
1938
1939 fclose( tst_file );
1940 }
1941
1942 free( dump_name );
1943 }
1944#endif /* DEBUG_HTTP */
1945
1946 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1947 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1948 close_rc = 0;
Daniel Veillard05d987b2003-10-08 11:54:57 +00001949 else {
1950 xmlChar msg[500];
1951 xmlStrPrintf(msg, 500,
1952 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
Daniel Veillardf012a642001-07-23 19:10:52 +00001953 http_mthd, content_lgth,
1954 "bytes to URI", ctxt->uri,
1955 "failed. HTTP return code:", http_rtn );
Daniel Veillard05d987b2003-10-08 11:54:57 +00001956 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1957 }
Daniel Veillardf012a642001-07-23 19:10:52 +00001958
1959 xmlNanoHTTPClose( http_ctxt );
1960 xmlFree( content_type );
1961 }
1962 }
1963
1964 /* Final cleanups */
1965
1966 xmlFreeHTTPWriteCtxt( ctxt );
1967
1968 return ( close_rc );
1969}
1970
1971/**
1972 * xmlIOHTTPClosePut
1973 *
1974 * @context: The I/O context
1975 *
1976 * Close the transmit HTTP I/O channel and actually send data using a PUT
1977 * HTTP method.
1978 */
1979static int
1980xmlIOHTTPClosePut( void * ctxt ) {
1981 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
1982}
1983
1984
1985/**
1986 * xmlIOHTTPClosePost
1987 *
1988 * @context: The I/O context
1989 *
1990 * Close the transmit HTTP I/O channel and actually send data using a POST
1991 * HTTP method.
1992 */
1993static int
1994xmlIOHTTPClosePost( void * ctxt ) {
1995 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
1996}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00001997#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00001998
Owen Taylor3473f882001-02-23 17:55:21 +00001999#endif /* LIBXML_HTTP_ENABLED */
2000
2001#ifdef LIBXML_FTP_ENABLED
2002/************************************************************************
2003 * *
2004 * I/O for FTP file accesses *
2005 * *
2006 ************************************************************************/
2007/**
2008 * xmlIOFTPMatch:
2009 * @filename: the URI for matching
2010 *
2011 * check if the URI matches an FTP one
2012 *
2013 * Returns 1 if matches, 0 otherwise
2014 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002015int
Owen Taylor3473f882001-02-23 17:55:21 +00002016xmlIOFTPMatch (const char *filename) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002017 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
Owen Taylor3473f882001-02-23 17:55:21 +00002018 return(1);
2019 return(0);
2020}
2021
2022/**
2023 * xmlIOFTPOpen:
2024 * @filename: the URI for matching
2025 *
2026 * open an FTP I/O channel
2027 *
2028 * Returns an I/O context or NULL in case of error
2029 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002030void *
Owen Taylor3473f882001-02-23 17:55:21 +00002031xmlIOFTPOpen (const char *filename) {
2032 return(xmlNanoFTPOpen(filename));
2033}
2034
2035/**
2036 * xmlIOFTPRead:
2037 * @context: the I/O context
2038 * @buffer: where to drop data
2039 * @len: number of bytes to write
2040 *
2041 * Read @len bytes to @buffer from the I/O channel.
2042 *
2043 * Returns the number of bytes written
2044 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002045int
Owen Taylor3473f882001-02-23 17:55:21 +00002046xmlIOFTPRead(void * context, char * buffer, int len) {
Daniel Veillard5ea30d72004-11-08 11:54:28 +00002047 if ((buffer == NULL) || (len < 0)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002048 return(xmlNanoFTPRead(context, &buffer[0], len));
2049}
2050
2051/**
2052 * xmlIOFTPClose:
2053 * @context: the I/O context
2054 *
2055 * Close an FTP I/O channel
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002056 *
2057 * Returns 0
Owen Taylor3473f882001-02-23 17:55:21 +00002058 */
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00002059int
Owen Taylor3473f882001-02-23 17:55:21 +00002060xmlIOFTPClose (void * context) {
Daniel Veillardf012a642001-07-23 19:10:52 +00002061 return ( xmlNanoFTPClose(context) );
Owen Taylor3473f882001-02-23 17:55:21 +00002062}
2063#endif /* LIBXML_FTP_ENABLED */
2064
2065
2066/**
2067 * xmlRegisterInputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002068 * @matchFunc: the xmlInputMatchCallback
2069 * @openFunc: the xmlInputOpenCallback
2070 * @readFunc: the xmlInputReadCallback
2071 * @closeFunc: the xmlInputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002072 *
2073 * Register a new set of I/O callback for handling parser input.
2074 *
2075 * Returns the registered handler number or -1 in case of error
2076 */
2077int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002078xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2079 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2080 xmlInputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002081 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2082 return(-1);
2083 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002084 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2085 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2086 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2087 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002088 xmlInputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002089 return(xmlInputCallbackNr++);
2090}
2091
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002092#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002093/**
2094 * xmlRegisterOutputCallbacks:
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002095 * @matchFunc: the xmlOutputMatchCallback
2096 * @openFunc: the xmlOutputOpenCallback
2097 * @writeFunc: the xmlOutputWriteCallback
2098 * @closeFunc: the xmlOutputCloseCallback
Owen Taylor3473f882001-02-23 17:55:21 +00002099 *
2100 * Register a new set of I/O callback for handling output.
2101 *
2102 * Returns the registered handler number or -1 in case of error
2103 */
2104int
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002105xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2106 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2107 xmlOutputCloseCallback closeFunc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002108 if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
2109 return(-1);
2110 }
Daniel Veillard56a4cb82001-03-24 17:00:36 +00002111 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2112 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2113 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2114 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
Daniel Veillard9ec26532003-09-23 07:43:19 +00002115 xmlOutputCallbackInitialized = 1;
Owen Taylor3473f882001-02-23 17:55:21 +00002116 return(xmlOutputCallbackNr++);
2117}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002118#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002119
2120/**
2121 * xmlRegisterDefaultInputCallbacks:
2122 *
2123 * Registers the default compiled-in I/O handlers.
2124 */
2125void
Owen Taylor3473f882001-02-23 17:55:21 +00002126xmlRegisterDefaultInputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002127(void) {
2128 if (xmlInputCallbackInitialized)
2129 return;
2130
2131 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2132 xmlFileRead, xmlFileClose);
2133#ifdef HAVE_ZLIB_H
2134 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2135 xmlGzfileRead, xmlGzfileClose);
2136#endif /* HAVE_ZLIB_H */
2137
2138#ifdef LIBXML_HTTP_ENABLED
2139 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2140 xmlIOHTTPRead, xmlIOHTTPClose);
2141#endif /* LIBXML_HTTP_ENABLED */
2142
2143#ifdef LIBXML_FTP_ENABLED
2144 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2145 xmlIOFTPRead, xmlIOFTPClose);
2146#endif /* LIBXML_FTP_ENABLED */
2147 xmlInputCallbackInitialized = 1;
2148}
2149
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002150#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002151/**
2152 * xmlRegisterDefaultOutputCallbacks:
2153 *
2154 * Registers the default compiled-in I/O handlers.
2155 */
2156void
Owen Taylor3473f882001-02-23 17:55:21 +00002157xmlRegisterDefaultOutputCallbacks
Owen Taylor3473f882001-02-23 17:55:21 +00002158(void) {
2159 if (xmlOutputCallbackInitialized)
2160 return;
2161
2162 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2163 xmlFileWrite, xmlFileClose);
Daniel Veillardf012a642001-07-23 19:10:52 +00002164
2165#ifdef LIBXML_HTTP_ENABLED
2166 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2167 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2168#endif
2169
Owen Taylor3473f882001-02-23 17:55:21 +00002170/*********************************
2171 No way a-priori to distinguish between gzipped files from
2172 uncompressed ones except opening if existing then closing
2173 and saving with same compression ratio ... a pain.
2174
2175#ifdef HAVE_ZLIB_H
2176 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2177 xmlGzfileWrite, xmlGzfileClose);
2178#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002179
2180 Nor FTP PUT ....
2181#ifdef LIBXML_FTP_ENABLED
2182 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2183 xmlIOFTPWrite, xmlIOFTPClose);
2184#endif
2185 **********************************/
2186 xmlOutputCallbackInitialized = 1;
2187}
2188
Daniel Veillardf012a642001-07-23 19:10:52 +00002189#ifdef LIBXML_HTTP_ENABLED
2190/**
Daniel Veillarda9b66d02002-12-11 14:23:49 +00002191 * xmlRegisterHTTPPostCallbacks:
Daniel Veillardf012a642001-07-23 19:10:52 +00002192 *
2193 * By default, libxml submits HTTP output requests using the "PUT" method.
2194 * Calling this method changes the HTTP output method to use the "POST"
2195 * method instead.
2196 *
2197 */
2198void
2199xmlRegisterHTTPPostCallbacks( void ) {
2200
2201 /* Register defaults if not done previously */
2202
2203 if ( xmlOutputCallbackInitialized == 0 )
2204 xmlRegisterDefaultOutputCallbacks( );
2205
2206 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2207 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2208 return;
2209}
2210#endif
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002211#endif /* LIBXML_OUTPUT_ENABLED */
Daniel Veillardf012a642001-07-23 19:10:52 +00002212
Owen Taylor3473f882001-02-23 17:55:21 +00002213/**
2214 * xmlAllocParserInputBuffer:
2215 * @enc: the charset encoding if known
2216 *
2217 * Create a buffered parser input for progressive parsing
2218 *
2219 * Returns the new parser input or NULL
2220 */
2221xmlParserInputBufferPtr
2222xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2223 xmlParserInputBufferPtr ret;
2224
2225 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2226 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002227 xmlIOErrMemory("creating input buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002228 return(NULL);
2229 }
2230 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002231 ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002232 if (ret->buffer == NULL) {
2233 xmlFree(ret);
2234 return(NULL);
2235 }
2236 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2237 ret->encoder = xmlGetCharEncodingHandler(enc);
2238 if (ret->encoder != NULL)
Daniel Veillard6155d8a2003-08-19 15:01:28 +00002239 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
Owen Taylor3473f882001-02-23 17:55:21 +00002240 else
2241 ret->raw = NULL;
2242 ret->readcallback = NULL;
2243 ret->closecallback = NULL;
2244 ret->context = NULL;
William M. Brackc07329e2003-09-08 01:57:30 +00002245 ret->compressed = -1;
Daniel Veillard36711902004-02-11 13:25:26 +00002246 ret->rawconsumed = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002247
2248 return(ret);
2249}
2250
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002251#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002252/**
2253 * xmlAllocOutputBuffer:
2254 * @encoder: the encoding converter or NULL
2255 *
2256 * Create a buffered parser output
2257 *
2258 * Returns the new parser output or NULL
2259 */
2260xmlOutputBufferPtr
2261xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2262 xmlOutputBufferPtr ret;
2263
2264 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2265 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002266 xmlIOErrMemory("creating output buffer");
Owen Taylor3473f882001-02-23 17:55:21 +00002267 return(NULL);
2268 }
2269 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2270 ret->buffer = xmlBufferCreate();
2271 if (ret->buffer == NULL) {
2272 xmlFree(ret);
2273 return(NULL);
2274 }
2275 ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
2276 ret->encoder = encoder;
2277 if (encoder != NULL) {
2278 ret->conv = xmlBufferCreateSize(4000);
2279 /*
2280 * This call is designed to initiate the encoder state
2281 */
2282 xmlCharEncOutFunc(encoder, ret->conv, NULL);
2283 } else
2284 ret->conv = NULL;
2285 ret->writecallback = NULL;
2286 ret->closecallback = NULL;
2287 ret->context = NULL;
2288 ret->written = 0;
2289
2290 return(ret);
2291}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002292#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002293
2294/**
2295 * xmlFreeParserInputBuffer:
2296 * @in: a buffered parser input
2297 *
2298 * Free up the memory used by a buffered parser input
2299 */
2300void
2301xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
Daniel Veillard8d8bf2c2003-09-17 19:36:25 +00002302 if (in == NULL) return;
2303
Owen Taylor3473f882001-02-23 17:55:21 +00002304 if (in->raw) {
2305 xmlBufferFree(in->raw);
2306 in->raw = NULL;
2307 }
2308 if (in->encoder != NULL) {
2309 xmlCharEncCloseFunc(in->encoder);
2310 }
2311 if (in->closecallback != NULL) {
2312 in->closecallback(in->context);
2313 }
2314 if (in->buffer != NULL) {
2315 xmlBufferFree(in->buffer);
2316 in->buffer = NULL;
2317 }
2318
Owen Taylor3473f882001-02-23 17:55:21 +00002319 xmlFree(in);
2320}
2321
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002322#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002323/**
2324 * xmlOutputBufferClose:
2325 * @out: a buffered output
2326 *
2327 * flushes and close the output I/O channel
2328 * and free up all the associated resources
2329 *
2330 * Returns the number of byte written or -1 in case of error.
2331 */
2332int
Daniel Veillard828ce832003-10-08 19:19:10 +00002333xmlOutputBufferClose(xmlOutputBufferPtr out)
2334{
Owen Taylor3473f882001-02-23 17:55:21 +00002335 int written;
Daniel Veillardf012a642001-07-23 19:10:52 +00002336 int err_rc = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002337
2338 if (out == NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002339 return (-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002340 if (out->writecallback != NULL)
Daniel Veillard828ce832003-10-08 19:19:10 +00002341 xmlOutputBufferFlush(out);
Owen Taylor3473f882001-02-23 17:55:21 +00002342 if (out->closecallback != NULL) {
Daniel Veillard828ce832003-10-08 19:19:10 +00002343 err_rc = out->closecallback(out->context);
Owen Taylor3473f882001-02-23 17:55:21 +00002344 }
2345 written = out->written;
2346 if (out->conv) {
2347 xmlBufferFree(out->conv);
Daniel Veillard828ce832003-10-08 19:19:10 +00002348 out->conv = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002349 }
2350 if (out->encoder != NULL) {
2351 xmlCharEncCloseFunc(out->encoder);
2352 }
2353 if (out->buffer != NULL) {
2354 xmlBufferFree(out->buffer);
Daniel Veillard828ce832003-10-08 19:19:10 +00002355 out->buffer = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002356 }
2357
Daniel Veillard828ce832003-10-08 19:19:10 +00002358 if (out->error)
2359 err_rc = -1;
Owen Taylor3473f882001-02-23 17:55:21 +00002360 xmlFree(out);
Daniel Veillard828ce832003-10-08 19:19:10 +00002361 return ((err_rc == 0) ? written : err_rc);
Owen Taylor3473f882001-02-23 17:55:21 +00002362}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002363#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002364
Daniel Veillard1b243b42004-06-08 10:16:42 +00002365xmlParserInputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002366__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
Owen Taylor3473f882001-02-23 17:55:21 +00002367 xmlParserInputBufferPtr ret;
Daniel Veillard388236f2001-07-08 18:35:48 +00002368 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002369 void *context = NULL;
2370
2371 if (xmlInputCallbackInitialized == 0)
2372 xmlRegisterDefaultInputCallbacks();
2373
2374 if (URI == NULL) return(NULL);
2375
2376 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002377 * Try to find one of the input accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002378 * Go in reverse to give precedence to user defined handlers.
Daniel Veillard388236f2001-07-08 18:35:48 +00002379 */
2380 if (context == NULL) {
2381 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2382 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2383 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002384 context = xmlInputCallbackTable[i].opencallback(URI);
Daniel Veillard847332a2003-10-18 11:29:40 +00002385 if (context != NULL) {
Daniel Veillard388236f2001-07-08 18:35:48 +00002386 break;
Daniel Veillard847332a2003-10-18 11:29:40 +00002387 }
Daniel Veillard388236f2001-07-08 18:35:48 +00002388 }
Owen Taylor3473f882001-02-23 17:55:21 +00002389 }
2390 }
2391 if (context == NULL) {
2392 return(NULL);
2393 }
2394
2395 /*
2396 * Allocate the Input buffer front-end.
2397 */
2398 ret = xmlAllocParserInputBuffer(enc);
2399 if (ret != NULL) {
2400 ret->context = context;
2401 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2402 ret->closecallback = xmlInputCallbackTable[i].closecallback;
William M. Brackc07329e2003-09-08 01:57:30 +00002403#ifdef HAVE_ZLIB_H
William M. Brackc5cbf992003-10-29 22:15:13 +00002404 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2405 (strcmp(URI, "-") != 0)) {
William M. Brackc07329e2003-09-08 01:57:30 +00002406 if (((z_stream *)context)->avail_in > 4) {
2407 char *cptr, buff4[4];
Daniel Veillard07cb8222003-09-10 10:51:05 +00002408 cptr = (char *) ((z_stream *)context)->next_in;
William M. Brackc07329e2003-09-08 01:57:30 +00002409 if (gzread(context, buff4, 4) == 4) {
2410 if (strncmp(buff4, cptr, 4) == 0)
2411 ret->compressed = 0;
2412 else
2413 ret->compressed = 1;
2414 gzrewind(context);
2415 }
2416 }
2417 }
2418#endif
Owen Taylor3473f882001-02-23 17:55:21 +00002419 }
William M. Brack42331a92004-07-29 07:07:16 +00002420 else
2421 xmlInputCallbackTable[i].closecallback (context);
2422
Owen Taylor3473f882001-02-23 17:55:21 +00002423 return(ret);
2424}
2425
2426/**
Daniel Veillard0335a842004-06-02 16:18:40 +00002427 * xmlParserInputBufferCreateFilename:
Owen Taylor3473f882001-02-23 17:55:21 +00002428 * @URI: a C string containing the URI or filename
Daniel Veillard0335a842004-06-02 16:18:40 +00002429 * @enc: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002430 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002431 * Create a buffered parser input for the progressive parsing of a file
2432 * If filename is "-' then we use stdin as the input.
Owen Taylor3473f882001-02-23 17:55:21 +00002433 * Automatic support for ZLIB/Compress compressed document is provided
2434 * by default if found at compile-time.
Daniel Veillard0335a842004-06-02 16:18:40 +00002435 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
Owen Taylor3473f882001-02-23 17:55:21 +00002436 *
Daniel Veillard0335a842004-06-02 16:18:40 +00002437 * Returns the new parser input or NULL
Owen Taylor3473f882001-02-23 17:55:21 +00002438 */
Daniel Veillard0335a842004-06-02 16:18:40 +00002439xmlParserInputBufferPtr
2440xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2441 if ((xmlParserInputBufferCreateFilenameValue)) {
2442 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2443 }
2444 return __xmlParserInputBufferCreateFilename(URI, enc);
2445}
2446
2447#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard1b243b42004-06-08 10:16:42 +00002448xmlOutputBufferPtr
Daniel Veillard0335a842004-06-02 16:18:40 +00002449__xmlOutputBufferCreateFilename(const char *URI,
Owen Taylor3473f882001-02-23 17:55:21 +00002450 xmlCharEncodingHandlerPtr encoder,
Daniel Veillard0335a842004-06-02 16:18:40 +00002451 int compression ATTRIBUTE_UNUSED) {
Owen Taylor3473f882001-02-23 17:55:21 +00002452 xmlOutputBufferPtr ret;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002453 xmlURIPtr puri;
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002454 int i = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00002455 void *context = NULL;
Daniel Veillard966a31e2004-05-09 02:58:44 +00002456 char *unescaped = NULL;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002457#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002458 int is_file_uri = 1;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002459#endif
Daniel Veillardf012a642001-07-23 19:10:52 +00002460
Owen Taylor3473f882001-02-23 17:55:21 +00002461 if (xmlOutputCallbackInitialized == 0)
2462 xmlRegisterDefaultOutputCallbacks();
2463
2464 if (URI == NULL) return(NULL);
2465
Daniel Veillard966a31e2004-05-09 02:58:44 +00002466 puri = xmlParseURI(URI);
2467 if (puri != NULL) {
Daniel Veillard8fcd2ca2005-07-03 14:42:56 +00002468#ifdef HAVE_ZLIB_H
Daniel Veillard18a65092004-05-11 15:57:42 +00002469 if ((puri->scheme != NULL) &&
2470 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
Daniel Veillard966a31e2004-05-09 02:58:44 +00002471 is_file_uri = 0;
Daniel Veillardc7e3cc42004-09-28 12:33:52 +00002472#endif
Daniel Veillard966a31e2004-05-09 02:58:44 +00002473 /*
2474 * try to limit the damages of the URI unescaping code.
2475 */
2476 if (puri->scheme != NULL)
2477 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2478 xmlFreeURI(puri);
2479 }
Owen Taylor3473f882001-02-23 17:55:21 +00002480
2481 /*
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002482 * Try to find one of the output accept method accepting that scheme
Owen Taylor3473f882001-02-23 17:55:21 +00002483 * Go in reverse to give precedence to user defined handlers.
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002484 * try with an unescaped version of the URI
Owen Taylor3473f882001-02-23 17:55:21 +00002485 */
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002486 if (unescaped != NULL) {
2487#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002488 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002489 context = xmlGzfileOpenW(unescaped, compression);
2490 if (context != NULL) {
2491 ret = xmlAllocOutputBuffer(encoder);
2492 if (ret != NULL) {
2493 ret->context = context;
2494 ret->writecallback = xmlGzfileWrite;
2495 ret->closecallback = xmlGzfileClose;
2496 }
2497 xmlFree(unescaped);
2498 return(ret);
2499 }
2500 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002501#endif
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002502 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2503 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2504 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2505#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2506 /* Need to pass compression parameter into HTTP open calls */
2507 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2508 context = xmlIOHTTPOpenW(unescaped, compression);
2509 else
2510#endif
2511 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2512 if (context != NULL)
2513 break;
2514 }
2515 }
2516 xmlFree(unescaped);
2517 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002518
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002519 /*
2520 * If this failed try with a non-escaped URI this may be a strange
2521 * filename
2522 */
2523 if (context == NULL) {
2524#ifdef HAVE_ZLIB_H
Daniel Veillard966a31e2004-05-09 02:58:44 +00002525 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002526 context = xmlGzfileOpenW(URI, compression);
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002527 if (context != NULL) {
2528 ret = xmlAllocOutputBuffer(encoder);
2529 if (ret != NULL) {
2530 ret->context = context;
2531 ret->writecallback = xmlGzfileWrite;
2532 ret->closecallback = xmlGzfileClose;
2533 }
2534 return(ret);
2535 }
2536 }
2537#endif
2538 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2539 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
Igor Zlatkovic5f9fada2003-02-19 14:51:00 +00002540 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
Daniel Veillardecb6f5b2001-08-15 08:47:42 +00002541#if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2542 /* Need to pass compression parameter into HTTP open calls */
2543 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2544 context = xmlIOHTTPOpenW(URI, compression);
2545 else
2546#endif
2547 context = xmlOutputCallbackTable[i].opencallback(URI);
2548 if (context != NULL)
2549 break;
2550 }
Owen Taylor3473f882001-02-23 17:55:21 +00002551 }
2552 }
Daniel Veillardf012a642001-07-23 19:10:52 +00002553
Owen Taylor3473f882001-02-23 17:55:21 +00002554 if (context == NULL) {
2555 return(NULL);
2556 }
2557
2558 /*
2559 * Allocate the Output buffer front-end.
2560 */
2561 ret = xmlAllocOutputBuffer(encoder);
2562 if (ret != NULL) {
2563 ret->context = context;
2564 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2565 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2566 }
2567 return(ret);
2568}
Daniel Veillard0335a842004-06-02 16:18:40 +00002569
2570/**
2571 * xmlOutputBufferCreateFilename:
2572 * @URI: a C string containing the URI or filename
2573 * @encoder: the encoding converter or NULL
2574 * @compression: the compression ration (0 none, 9 max).
2575 *
2576 * Create a buffered output for the progressive saving of a file
2577 * If filename is "-' then we use stdout as the output.
2578 * Automatic support for ZLIB/Compress compressed document is provided
2579 * by default if found at compile-time.
2580 * TODO: currently if compression is set, the library only support
2581 * writing to a local file.
2582 *
2583 * Returns the new output or NULL
2584 */
2585xmlOutputBufferPtr
2586xmlOutputBufferCreateFilename(const char *URI,
2587 xmlCharEncodingHandlerPtr encoder,
2588 int compression ATTRIBUTE_UNUSED) {
2589 if ((xmlOutputBufferCreateFilenameValue)) {
2590 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2591 }
2592 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2593}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002594#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002595
2596/**
2597 * xmlParserInputBufferCreateFile:
2598 * @file: a FILE*
2599 * @enc: the charset encoding if known
2600 *
2601 * Create a buffered parser input for the progressive parsing of a FILE *
2602 * buffered C I/O
2603 *
2604 * Returns the new parser input or NULL
2605 */
2606xmlParserInputBufferPtr
2607xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2608 xmlParserInputBufferPtr ret;
2609
2610 if (xmlInputCallbackInitialized == 0)
2611 xmlRegisterDefaultInputCallbacks();
2612
2613 if (file == NULL) return(NULL);
2614
2615 ret = xmlAllocParserInputBuffer(enc);
2616 if (ret != NULL) {
2617 ret->context = file;
2618 ret->readcallback = xmlFileRead;
2619 ret->closecallback = xmlFileFlush;
2620 }
2621
2622 return(ret);
2623}
2624
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002625#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002626/**
2627 * xmlOutputBufferCreateFile:
2628 * @file: a FILE*
2629 * @encoder: the encoding converter or NULL
2630 *
2631 * Create a buffered output for the progressive saving to a FILE *
2632 * buffered C I/O
2633 *
2634 * Returns the new parser output or NULL
2635 */
2636xmlOutputBufferPtr
2637xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2638 xmlOutputBufferPtr ret;
2639
2640 if (xmlOutputCallbackInitialized == 0)
2641 xmlRegisterDefaultOutputCallbacks();
2642
2643 if (file == NULL) return(NULL);
2644
2645 ret = xmlAllocOutputBuffer(encoder);
2646 if (ret != NULL) {
2647 ret->context = file;
2648 ret->writecallback = xmlFileWrite;
2649 ret->closecallback = xmlFileFlush;
2650 }
2651
2652 return(ret);
2653}
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002654
2655/**
2656 * xmlOutputBufferCreateBuffer:
2657 * @buffer: a xmlBufferPtr
2658 * @encoder: the encoding converter or NULL
2659 *
2660 * Create a buffered output for the progressive saving to a xmlBuffer
2661 *
2662 * Returns the new parser output or NULL
2663 */
2664xmlOutputBufferPtr
2665xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2666 xmlCharEncodingHandlerPtr encoder) {
2667 xmlOutputBufferPtr ret;
2668
2669 if (buffer == NULL) return(NULL);
2670
Rob Richardsa44f2342005-11-09 18:03:45 +00002671 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2672 xmlBufferWrite,
2673 (xmlOutputCloseCallback)
Daniel Veillard4d3866c2005-11-13 12:43:59 +00002674 NULL, (void *) buffer, encoder);
Daniel Veillard9a00fd22005-11-09 08:56:26 +00002675
2676 return(ret);
2677}
2678
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002679#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002680
2681/**
2682 * xmlParserInputBufferCreateFd:
2683 * @fd: a file descriptor number
2684 * @enc: the charset encoding if known
2685 *
2686 * Create a buffered parser input for the progressive parsing for the input
2687 * from a file descriptor
2688 *
2689 * Returns the new parser input or NULL
2690 */
2691xmlParserInputBufferPtr
2692xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2693 xmlParserInputBufferPtr ret;
2694
2695 if (fd < 0) return(NULL);
2696
2697 ret = xmlAllocParserInputBuffer(enc);
2698 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002699 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002700 ret->readcallback = xmlFdRead;
2701 ret->closecallback = xmlFdClose;
2702 }
2703
2704 return(ret);
2705}
2706
2707/**
2708 * xmlParserInputBufferCreateMem:
2709 * @mem: the memory input
2710 * @size: the length of the memory block
2711 * @enc: the charset encoding if known
2712 *
2713 * Create a buffered parser input for the progressive parsing for the input
2714 * from a memory area.
2715 *
2716 * Returns the new parser input or NULL
2717 */
2718xmlParserInputBufferPtr
2719xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2720 xmlParserInputBufferPtr ret;
William M. Bracka3215c72004-07-31 16:24:01 +00002721 int errcode;
Owen Taylor3473f882001-02-23 17:55:21 +00002722
2723 if (size <= 0) return(NULL);
2724 if (mem == NULL) return(NULL);
2725
2726 ret = xmlAllocParserInputBuffer(enc);
2727 if (ret != NULL) {
2728 ret->context = (void *) mem;
2729 ret->readcallback = (xmlInputReadCallback) xmlNop;
2730 ret->closecallback = NULL;
William M. Bracka3215c72004-07-31 16:24:01 +00002731 errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
2732 if (errcode != 0) {
2733 xmlFree(ret);
2734 return(NULL);
2735 }
Owen Taylor3473f882001-02-23 17:55:21 +00002736 }
2737
2738 return(ret);
2739}
2740
2741/**
Daniel Veillard53350552003-09-18 13:35:51 +00002742 * xmlParserInputBufferCreateStatic:
2743 * @mem: the memory input
2744 * @size: the length of the memory block
2745 * @enc: the charset encoding if known
2746 *
2747 * Create a buffered parser input for the progressive parsing for the input
2748 * from an immutable memory area. This will not copy the memory area to
2749 * the buffer, but the memory is expected to be available until the end of
2750 * the parsing, this is useful for example when using mmap'ed file.
2751 *
2752 * Returns the new parser input or NULL
2753 */
2754xmlParserInputBufferPtr
2755xmlParserInputBufferCreateStatic(const char *mem, int size,
2756 xmlCharEncoding enc) {
2757 xmlParserInputBufferPtr ret;
2758
2759 if (size <= 0) return(NULL);
2760 if (mem == NULL) return(NULL);
2761
2762 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2763 if (ret == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002764 xmlIOErrMemory("creating input buffer");
Daniel Veillard53350552003-09-18 13:35:51 +00002765 return(NULL);
2766 }
2767 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
Daniel Veillarde72c5082003-09-19 12:44:05 +00002768 ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
Daniel Veillard53350552003-09-18 13:35:51 +00002769 if (ret->buffer == NULL) {
2770 xmlFree(ret);
2771 return(NULL);
2772 }
2773 ret->encoder = xmlGetCharEncodingHandler(enc);
2774 if (ret->encoder != NULL)
2775 ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
2776 else
2777 ret->raw = NULL;
2778 ret->compressed = -1;
2779 ret->context = (void *) mem;
2780 ret->readcallback = NULL;
2781 ret->closecallback = NULL;
2782
2783 return(ret);
2784}
2785
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002786#ifdef LIBXML_OUTPUT_ENABLED
Daniel Veillard53350552003-09-18 13:35:51 +00002787/**
Owen Taylor3473f882001-02-23 17:55:21 +00002788 * xmlOutputBufferCreateFd:
2789 * @fd: a file descriptor number
2790 * @encoder: the encoding converter or NULL
2791 *
2792 * Create a buffered output for the progressive saving
2793 * to a file descriptor
2794 *
2795 * Returns the new parser output or NULL
2796 */
2797xmlOutputBufferPtr
2798xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
2799 xmlOutputBufferPtr ret;
2800
2801 if (fd < 0) return(NULL);
2802
2803 ret = xmlAllocOutputBuffer(encoder);
2804 if (ret != NULL) {
Daniel Veillard8fcc4942001-07-17 20:07:33 +00002805 ret->context = (void *) (long) fd;
Owen Taylor3473f882001-02-23 17:55:21 +00002806 ret->writecallback = xmlFdWrite;
Daniel Veillard7db38712002-02-07 16:39:11 +00002807 ret->closecallback = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +00002808 }
2809
2810 return(ret);
2811}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002812#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002813
2814/**
2815 * xmlParserInputBufferCreateIO:
2816 * @ioread: an I/O read function
2817 * @ioclose: an I/O close function
2818 * @ioctx: an I/O handler
2819 * @enc: the charset encoding if known
2820 *
2821 * Create a buffered parser input for the progressive parsing for the input
2822 * from an I/O handler
2823 *
2824 * Returns the new parser input or NULL
2825 */
2826xmlParserInputBufferPtr
2827xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
2828 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
2829 xmlParserInputBufferPtr ret;
2830
2831 if (ioread == NULL) return(NULL);
2832
2833 ret = xmlAllocParserInputBuffer(enc);
2834 if (ret != NULL) {
2835 ret->context = (void *) ioctx;
2836 ret->readcallback = ioread;
2837 ret->closecallback = ioclose;
2838 }
2839
2840 return(ret);
2841}
2842
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002843#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00002844/**
2845 * xmlOutputBufferCreateIO:
2846 * @iowrite: an I/O write function
2847 * @ioclose: an I/O close function
2848 * @ioctx: an I/O handler
Daniel Veillard9d06d302002-01-22 18:15:52 +00002849 * @encoder: the charset encoding if known
Owen Taylor3473f882001-02-23 17:55:21 +00002850 *
2851 * Create a buffered output for the progressive saving
2852 * to an I/O handler
2853 *
2854 * Returns the new parser output or NULL
2855 */
2856xmlOutputBufferPtr
2857xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
2858 xmlOutputCloseCallback ioclose, void *ioctx,
2859 xmlCharEncodingHandlerPtr encoder) {
2860 xmlOutputBufferPtr ret;
2861
2862 if (iowrite == NULL) return(NULL);
2863
2864 ret = xmlAllocOutputBuffer(encoder);
2865 if (ret != NULL) {
2866 ret->context = (void *) ioctx;
2867 ret->writecallback = iowrite;
2868 ret->closecallback = ioclose;
2869 }
2870
2871 return(ret);
2872}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00002873#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00002874
2875/**
Daniel Veillard1b243b42004-06-08 10:16:42 +00002876 * xmlParserInputBufferCreateFilenameDefault:
2877 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
2878 *
2879 * Registers a callback for URI input file handling
2880 *
2881 * Returns the old value of the registration function
2882 */
2883xmlParserInputBufferCreateFilenameFunc
2884xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
2885{
2886 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
2887 if (old == NULL) {
2888 old = __xmlParserInputBufferCreateFilename;
2889 }
2890
2891 xmlParserInputBufferCreateFilenameValue = func;
2892 return(old);
2893}
2894
2895/**
2896 * xmlOutputBufferCreateFilenameDefault:
2897 * @func: function pointer to the new OutputBufferCreateFilenameFunc
2898 *
2899 * Registers a callback for URI output file handling
2900 *
2901 * Returns the old value of the registration function
2902 */
2903xmlOutputBufferCreateFilenameFunc
2904xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2905{
2906 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2907#ifdef LIBXML_OUTPUT_ENABLED
2908 if (old == NULL) {
2909 old = __xmlOutputBufferCreateFilename;
2910 }
2911#endif
2912 xmlOutputBufferCreateFilenameValue = func;
2913 return(old);
2914}
2915
2916/**
Owen Taylor3473f882001-02-23 17:55:21 +00002917 * xmlParserInputBufferPush:
2918 * @in: a buffered parser input
2919 * @len: the size in bytes of the array.
2920 * @buf: an char array
2921 *
2922 * Push the content of the arry in the input buffer
2923 * This routine handle the I18N transcoding to internal UTF-8
2924 * This is used when operating the parser in progressive (push) mode.
2925 *
2926 * Returns the number of chars read and stored in the buffer, or -1
2927 * in case of error.
2928 */
2929int
2930xmlParserInputBufferPush(xmlParserInputBufferPtr in,
2931 int len, const char *buf) {
2932 int nbchars = 0;
William M. Bracka3215c72004-07-31 16:24:01 +00002933 int ret;
Owen Taylor3473f882001-02-23 17:55:21 +00002934
2935 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002936 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002937 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00002938 unsigned int use;
2939
Owen Taylor3473f882001-02-23 17:55:21 +00002940 /*
2941 * Store the data in the incoming raw buffer
2942 */
2943 if (in->raw == NULL) {
2944 in->raw = xmlBufferCreate();
2945 }
William M. Bracka3215c72004-07-31 16:24:01 +00002946 ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
2947 if (ret != 0)
2948 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002949
2950 /*
2951 * convert as much as possible to the parser reading buffer.
2952 */
Daniel Veillard36711902004-02-11 13:25:26 +00002953 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00002954 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
2955 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00002956 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00002957 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00002958 return(-1);
2959 }
Daniel Veillard36711902004-02-11 13:25:26 +00002960 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00002961 } else {
2962 nbchars = len;
William M. Bracka3215c72004-07-31 16:24:01 +00002963 ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
2964 if (ret != 0)
2965 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00002966 }
2967#ifdef DEBUG_INPUT
2968 xmlGenericError(xmlGenericErrorContext,
2969 "I/O: pushed %d chars, buffer %d/%d\n",
2970 nbchars, in->buffer->use, in->buffer->size);
2971#endif
2972 return(nbchars);
2973}
2974
2975/**
Daniel Veillardddffd2a2002-03-05 20:28:20 +00002976 * endOfInput:
2977 *
2978 * When reading from an Input channel indicated end of file or error
2979 * don't reread from it again.
2980 */
2981static int
2982endOfInput (void * context ATTRIBUTE_UNUSED,
2983 char * buffer ATTRIBUTE_UNUSED,
2984 int len ATTRIBUTE_UNUSED) {
2985 return(0);
2986}
2987
2988/**
Owen Taylor3473f882001-02-23 17:55:21 +00002989 * xmlParserInputBufferGrow:
2990 * @in: a buffered parser input
2991 * @len: indicative value of the amount of chars to read
2992 *
2993 * Grow up the content of the input buffer, the old data are preserved
2994 * This routine handle the I18N transcoding to internal UTF-8
2995 * This routine is used when operating the parser in normal (pull) mode
2996 *
Daniel Veillardcbaf3992001-12-31 16:16:02 +00002997 * TODO: one should be able to remove one extra copy by copying directly
Owen Taylor3473f882001-02-23 17:55:21 +00002998 * onto in->buffer or in->raw
2999 *
3000 * Returns the number of chars read and stored in the buffer, or -1
3001 * in case of error.
3002 */
3003int
3004xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3005 char *buffer = NULL;
3006 int res = 0;
3007 int nbchars = 0;
3008 int buffree;
Daniel Veillard9e412302002-06-10 15:59:44 +00003009 unsigned int needSize;
Owen Taylor3473f882001-02-23 17:55:21 +00003010
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003011 if ((in == NULL) || (in->error)) return(-1);
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003012 if ((len <= MINLEN) && (len != 4))
Owen Taylor3473f882001-02-23 17:55:21 +00003013 len = MINLEN;
Daniel Veillard6155d8a2003-08-19 15:01:28 +00003014
Owen Taylor3473f882001-02-23 17:55:21 +00003015 buffree = in->buffer->size - in->buffer->use;
3016 if (buffree <= 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003017 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003018 in->error = XML_IO_BUFFER_FULL;
William M. Bracka3215c72004-07-31 16:24:01 +00003019 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003020 }
Owen Taylor3473f882001-02-23 17:55:21 +00003021
Daniel Veillarde5354492002-05-16 08:43:22 +00003022 needSize = in->buffer->use + len + 1;
3023 if (needSize > in->buffer->size){
3024 if (!xmlBufferResize(in->buffer, needSize)){
Daniel Veillard05d987b2003-10-08 11:54:57 +00003025 xmlIOErrMemory("growing input buffer");
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003026 in->error = XML_ERR_NO_MEMORY;
William M. Bracka3215c72004-07-31 16:24:01 +00003027 return(-1);
Daniel Veillarde5354492002-05-16 08:43:22 +00003028 }
Owen Taylor3473f882001-02-23 17:55:21 +00003029 }
Daniel Veillarde5354492002-05-16 08:43:22 +00003030 buffer = (char *)&in->buffer->content[in->buffer->use];
Owen Taylor3473f882001-02-23 17:55:21 +00003031
3032 /*
3033 * Call the read method for this I/O type.
3034 */
3035 if (in->readcallback != NULL) {
3036 res = in->readcallback(in->context, &buffer[0], len);
Daniel Veillardddffd2a2002-03-05 20:28:20 +00003037 if (res <= 0)
3038 in->readcallback = endOfInput;
Owen Taylor3473f882001-02-23 17:55:21 +00003039 } else {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003040 xmlIOErr(XML_IO_NO_INPUT, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003041 in->error = XML_IO_NO_INPUT;
Owen Taylor3473f882001-02-23 17:55:21 +00003042 return(-1);
3043 }
3044 if (res < 0) {
Owen Taylor3473f882001-02-23 17:55:21 +00003045 return(-1);
3046 }
3047 len = res;
3048 if (in->encoder != NULL) {
Daniel Veillard36711902004-02-11 13:25:26 +00003049 unsigned int use;
3050
Owen Taylor3473f882001-02-23 17:55:21 +00003051 /*
3052 * Store the data in the incoming raw buffer
3053 */
3054 if (in->raw == NULL) {
3055 in->raw = xmlBufferCreate();
3056 }
William M. Bracka3215c72004-07-31 16:24:01 +00003057 res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
3058 if (res != 0)
3059 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003060
3061 /*
3062 * convert as much as possible to the parser reading buffer.
3063 */
Daniel Veillard36711902004-02-11 13:25:26 +00003064 use = in->raw->use;
Owen Taylor3473f882001-02-23 17:55:21 +00003065 nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
3066 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003067 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003068 in->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003069 return(-1);
3070 }
Daniel Veillard36711902004-02-11 13:25:26 +00003071 in->rawconsumed += (use - in->raw->use);
Owen Taylor3473f882001-02-23 17:55:21 +00003072 } else {
3073 nbchars = len;
Daniel Veillarde5354492002-05-16 08:43:22 +00003074 in->buffer->use += nbchars;
3075 buffer[nbchars] = 0;
Owen Taylor3473f882001-02-23 17:55:21 +00003076 }
3077#ifdef DEBUG_INPUT
3078 xmlGenericError(xmlGenericErrorContext,
3079 "I/O: read %d chars, buffer %d/%d\n",
3080 nbchars, in->buffer->use, in->buffer->size);
3081#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003082 return(nbchars);
3083}
3084
3085/**
3086 * xmlParserInputBufferRead:
3087 * @in: a buffered parser input
3088 * @len: indicative value of the amount of chars to read
3089 *
3090 * Refresh the content of the input buffer, the old data are considered
3091 * consumed
3092 * This routine handle the I18N transcoding to internal UTF-8
3093 *
3094 * Returns the number of chars read and stored in the buffer, or -1
3095 * in case of error.
3096 */
3097int
3098xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003099 if ((in == NULL) || (in->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003100 if (in->readcallback != NULL)
3101 return(xmlParserInputBufferGrow(in, len));
Daniel Veillard53350552003-09-18 13:35:51 +00003102 else if ((in->buffer != NULL) &&
3103 (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
3104 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +00003105 else
3106 return(-1);
3107}
3108
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003109#ifdef LIBXML_OUTPUT_ENABLED
Owen Taylor3473f882001-02-23 17:55:21 +00003110/**
3111 * xmlOutputBufferWrite:
3112 * @out: a buffered parser output
3113 * @len: the size in bytes of the array.
3114 * @buf: an char array
3115 *
3116 * Write the content of the array in the output I/O buffer
3117 * This routine handle the I18N transcoding from internal UTF-8
3118 * The buffer is lossless, i.e. will store in case of partial
3119 * or delayed writes.
3120 *
3121 * Returns the number of chars immediately written, or -1
3122 * in case of error.
3123 */
3124int
3125xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3126 int nbchars = 0; /* number of chars to output to I/O */
3127 int ret; /* return from function call */
3128 int written = 0; /* number of char written to I/O so far */
3129 int chunk; /* number of byte curreent processed from buf */
3130
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003131 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003132 if (len < 0) return(0);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003133 if (out->error) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003134
3135 do {
3136 chunk = len;
3137 if (chunk > 4 * MINLEN)
3138 chunk = 4 * MINLEN;
3139
3140 /*
3141 * first handle encoding stuff.
3142 */
3143 if (out->encoder != NULL) {
3144 /*
3145 * Store the data in the incoming raw buffer
3146 */
3147 if (out->conv == NULL) {
3148 out->conv = xmlBufferCreate();
3149 }
William M. Bracka3215c72004-07-31 16:24:01 +00003150 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3151 if (ret != 0)
3152 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003153
3154 if ((out->buffer->use < MINLEN) && (chunk == len))
3155 goto done;
3156
3157 /*
3158 * convert as much as possible to the parser reading buffer.
3159 */
3160 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
Daniel Veillard809faa52003-02-10 15:43:53 +00003161 if ((ret < 0) && (ret != -3)) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003162 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003163 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003164 return(-1);
3165 }
3166 nbchars = out->conv->use;
3167 } else {
William M. Bracka3215c72004-07-31 16:24:01 +00003168 ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
3169 if (ret != 0)
3170 return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003171 nbchars = out->buffer->use;
3172 }
3173 buf += chunk;
3174 len -= chunk;
3175
3176 if ((nbchars < MINLEN) && (len <= 0))
3177 goto done;
3178
3179 if (out->writecallback) {
3180 /*
3181 * second write the stuff to the I/O channel
3182 */
3183 if (out->encoder != NULL) {
3184 ret = out->writecallback(out->context,
3185 (const char *)out->conv->content, nbchars);
3186 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003187 xmlBufferShrink(out->conv, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003188 } else {
3189 ret = out->writecallback(out->context,
3190 (const char *)out->buffer->content, nbchars);
3191 if (ret >= 0)
Daniel Veillardedddff92001-05-02 10:58:52 +00003192 xmlBufferShrink(out->buffer, ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003193 }
3194 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003195 xmlIOErr(XML_IO_WRITE, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003196 out->error = XML_IO_WRITE;
Owen Taylor3473f882001-02-23 17:55:21 +00003197 return(ret);
3198 }
3199 out->written += ret;
3200 }
3201 written += nbchars;
3202 } while (len > 0);
3203
3204done:
3205#ifdef DEBUG_INPUT
3206 xmlGenericError(xmlGenericErrorContext,
3207 "I/O: wrote %d chars\n", written);
3208#endif
3209 return(written);
3210}
3211
3212/**
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003213 * xmlEscapeContent:
3214 * @out: a pointer to an array of bytes to store the result
3215 * @outlen: the length of @out
3216 * @in: a pointer to an array of unescaped UTF-8 bytes
3217 * @inlen: the length of @in
3218 *
3219 * Take a block of UTF-8 chars in and escape them.
3220 * Returns 0 if success, or -1 otherwise
3221 * The value of @inlen after return is the number of octets consumed
3222 * if the return value is positive, else unpredictable.
3223 * The value of @outlen after return is the number of octets consumed.
3224 */
3225static int
3226xmlEscapeContent(unsigned char* out, int *outlen,
3227 const xmlChar* in, int *inlen) {
3228 unsigned char* outstart = out;
3229 const unsigned char* base = in;
3230 unsigned char* outend = out + *outlen;
3231 const unsigned char* inend;
3232
3233 inend = in + (*inlen);
3234
3235 while ((in < inend) && (out < outend)) {
3236 if (*in == '<') {
3237 if (outend - out < 4) break;
3238 *out++ = '&';
3239 *out++ = 'l';
3240 *out++ = 't';
3241 *out++ = ';';
3242 } else if (*in == '>') {
3243 if (outend - out < 4) break;
3244 *out++ = '&';
3245 *out++ = 'g';
3246 *out++ = 't';
3247 *out++ = ';';
3248 } else if (*in == '&') {
3249 if (outend - out < 5) break;
3250 *out++ = '&';
3251 *out++ = 'a';
3252 *out++ = 'm';
3253 *out++ = 'p';
3254 *out++ = ';';
3255 } else if (*in == '\r') {
3256 if (outend - out < 5) break;
3257 *out++ = '&';
3258 *out++ = '#';
3259 *out++ = '1';
3260 *out++ = '3';
3261 *out++ = ';';
3262 } else {
3263 *out++ = (unsigned char) *in;
3264 }
3265 ++in;
3266 }
3267 *outlen = out - outstart;
3268 *inlen = in - base;
3269 return(0);
3270}
3271
3272/**
3273 * xmlOutputBufferWriteEscape:
3274 * @out: a buffered parser output
3275 * @str: a zero terminated UTF-8 string
Daniel Veillardee8960b2004-05-14 03:25:14 +00003276 * @escaping: an optional escaping function (or NULL)
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003277 *
3278 * Write the content of the string in the output I/O buffer
3279 * This routine escapes the caracters and then handle the I18N
3280 * transcoding from internal UTF-8
3281 * The buffer is lossless, i.e. will store in case of partial
3282 * or delayed writes.
3283 *
3284 * Returns the number of chars immediately written, or -1
3285 * in case of error.
3286 */
3287int
Daniel Veillardee8960b2004-05-14 03:25:14 +00003288xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3289 xmlCharEncodingOutputFunc escaping) {
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003290 int nbchars = 0; /* number of chars to output to I/O */
3291 int ret; /* return from function call */
3292 int written = 0; /* number of char written to I/O so far */
Daniel Veillard71b95632004-08-31 12:15:36 +00003293 int oldwritten=0;/* loop guard */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003294 int chunk; /* number of byte currently processed from str */
3295 int len; /* number of bytes in str */
3296 int cons; /* byte from str consumed */
3297
Daniel Veillardce244ad2004-11-05 10:03:46 +00003298 if ((out == NULL) || (out->error) || (str == NULL) ||
3299 (out->buffer == NULL) ||
3300 (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003301 len = strlen((const char *)str);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003302 if (len < 0) return(0);
3303 if (out->error) return(-1);
Daniel Veillardee8960b2004-05-14 03:25:14 +00003304 if (escaping == NULL) escaping = xmlEscapeContent;
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003305
3306 do {
Daniel Veillard71b95632004-08-31 12:15:36 +00003307 oldwritten = written;
3308
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003309 /*
3310 * how many bytes to consume and how many bytes to store.
3311 */
3312 cons = len;
3313 chunk = (out->buffer->size - out->buffer->use) - 1;
3314
3315 /*
3316 * first handle encoding stuff.
3317 */
3318 if (out->encoder != NULL) {
3319 /*
3320 * Store the data in the incoming raw buffer
3321 */
3322 if (out->conv == NULL) {
3323 out->conv = xmlBufferCreate();
3324 }
Daniel Veillardee8960b2004-05-14 03:25:14 +00003325 ret = escaping(out->buffer->content + out->buffer->use ,
3326 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003327 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003328 return(-1);
3329 out->buffer->use += chunk;
3330 out->buffer->content[out->buffer->use] = 0;
3331
3332 if ((out->buffer->use < MINLEN) && (cons == len))
3333 goto done;
3334
3335 /*
3336 * convert as much as possible to the output buffer.
3337 */
3338 ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3339 if ((ret < 0) && (ret != -3)) {
3340 xmlIOErr(XML_IO_ENCODER, NULL);
3341 out->error = XML_IO_ENCODER;
3342 return(-1);
3343 }
3344 nbchars = out->conv->use;
3345 } else {
Daniel Veillardee8960b2004-05-14 03:25:14 +00003346 ret = escaping(out->buffer->content + out->buffer->use ,
3347 &chunk, str, &cons);
William M. Brack66e40b12004-11-26 15:45:19 +00003348 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003349 return(-1);
3350 out->buffer->use += chunk;
3351 out->buffer->content[out->buffer->use] = 0;
3352 nbchars = out->buffer->use;
3353 }
3354 str += cons;
3355 len -= cons;
3356
3357 if ((nbchars < MINLEN) && (len <= 0))
3358 goto done;
3359
3360 if (out->writecallback) {
3361 /*
3362 * second write the stuff to the I/O channel
3363 */
3364 if (out->encoder != NULL) {
3365 ret = out->writecallback(out->context,
3366 (const char *)out->conv->content, nbchars);
3367 if (ret >= 0)
3368 xmlBufferShrink(out->conv, ret);
3369 } else {
3370 ret = out->writecallback(out->context,
3371 (const char *)out->buffer->content, nbchars);
3372 if (ret >= 0)
3373 xmlBufferShrink(out->buffer, ret);
3374 }
3375 if (ret < 0) {
3376 xmlIOErr(XML_IO_WRITE, NULL);
3377 out->error = XML_IO_WRITE;
3378 return(ret);
3379 }
3380 out->written += ret;
Daniel Veillard83a75e02004-05-14 21:50:42 +00003381 } else if (out->buffer->size - out->buffer->use < MINLEN) {
3382 xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003383 }
3384 written += nbchars;
Daniel Veillard71b95632004-08-31 12:15:36 +00003385 } while ((len > 0) && (oldwritten != written));
Daniel Veillard5d1a4d82004-05-13 14:31:25 +00003386
3387done:
3388#ifdef DEBUG_INPUT
3389 xmlGenericError(xmlGenericErrorContext,
3390 "I/O: wrote %d chars\n", written);
3391#endif
3392 return(written);
3393}
3394
3395/**
Owen Taylor3473f882001-02-23 17:55:21 +00003396 * xmlOutputBufferWriteString:
3397 * @out: a buffered parser output
3398 * @str: a zero terminated C string
3399 *
3400 * Write the content of the string in the output I/O buffer
3401 * This routine handle the I18N transcoding from internal UTF-8
3402 * The buffer is lossless, i.e. will store in case of partial
3403 * or delayed writes.
3404 *
3405 * Returns the number of chars immediately written, or -1
3406 * in case of error.
3407 */
3408int
3409xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3410 int len;
3411
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003412 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003413 if (str == NULL)
3414 return(-1);
3415 len = strlen(str);
3416
3417 if (len > 0)
3418 return(xmlOutputBufferWrite(out, len, str));
3419 return(len);
3420}
3421
3422/**
3423 * xmlOutputBufferFlush:
3424 * @out: a buffered output
3425 *
3426 * flushes the output I/O channel
3427 *
3428 * Returns the number of byte written or -1 in case of error.
3429 */
3430int
3431xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3432 int nbchars = 0, ret = 0;
3433
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003434 if ((out == NULL) || (out->error)) return(-1);
Owen Taylor3473f882001-02-23 17:55:21 +00003435 /*
3436 * first handle encoding stuff.
3437 */
3438 if ((out->conv != NULL) && (out->encoder != NULL)) {
3439 /*
3440 * convert as much as possible to the parser reading buffer.
3441 */
3442 nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
3443 if (nbchars < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003444 xmlIOErr(XML_IO_ENCODER, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003445 out->error = XML_IO_ENCODER;
Owen Taylor3473f882001-02-23 17:55:21 +00003446 return(-1);
3447 }
3448 }
3449
3450 /*
3451 * second flush the stuff to the I/O channel
3452 */
3453 if ((out->conv != NULL) && (out->encoder != NULL) &&
3454 (out->writecallback != NULL)) {
3455 ret = out->writecallback(out->context,
3456 (const char *)out->conv->content, out->conv->use);
3457 if (ret >= 0)
3458 xmlBufferShrink(out->conv, ret);
3459 } else if (out->writecallback != NULL) {
3460 ret = out->writecallback(out->context,
3461 (const char *)out->buffer->content, out->buffer->use);
3462 if (ret >= 0)
3463 xmlBufferShrink(out->buffer, ret);
3464 }
3465 if (ret < 0) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003466 xmlIOErr(XML_IO_FLUSH, NULL);
Daniel Veillard97bf4d02003-10-08 18:58:28 +00003467 out->error = XML_IO_FLUSH;
Owen Taylor3473f882001-02-23 17:55:21 +00003468 return(ret);
3469 }
3470 out->written += ret;
3471
3472#ifdef DEBUG_INPUT
3473 xmlGenericError(xmlGenericErrorContext,
3474 "I/O: flushed %d chars\n", ret);
3475#endif
3476 return(ret);
3477}
Daniel Veillarda9cce9c2003-09-29 13:20:24 +00003478#endif /* LIBXML_OUTPUT_ENABLED */
Owen Taylor3473f882001-02-23 17:55:21 +00003479
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003480/**
Owen Taylor3473f882001-02-23 17:55:21 +00003481 * xmlParserGetDirectory:
3482 * @filename: the path to a file
3483 *
3484 * lookup the directory for that file
3485 *
3486 * Returns a new allocated string containing the directory, or NULL.
3487 */
3488char *
3489xmlParserGetDirectory(const char *filename) {
3490 char *ret = NULL;
3491 char dir[1024];
3492 char *cur;
3493 char sep = '/';
3494
Igor Zlatkovic9181cc02002-09-29 17:51:06 +00003495#ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3496 return NULL;
3497#endif
3498
Owen Taylor3473f882001-02-23 17:55:21 +00003499 if (xmlInputCallbackInitialized == 0)
3500 xmlRegisterDefaultInputCallbacks();
3501
3502 if (filename == NULL) return(NULL);
Daniel Veillard3c5ed912002-01-08 10:36:16 +00003503#if defined(WIN32) && !defined(__CYGWIN__)
Owen Taylor3473f882001-02-23 17:55:21 +00003504 sep = '\\';
3505#endif
3506
3507 strncpy(dir, filename, 1023);
3508 dir[1023] = 0;
3509 cur = &dir[strlen(dir)];
3510 while (cur > dir) {
3511 if (*cur == sep) break;
3512 cur --;
3513 }
3514 if (*cur == sep) {
3515 if (cur == dir) dir[1] = 0;
3516 else *cur = 0;
3517 ret = xmlMemStrdup(dir);
3518 } else {
3519 if (getcwd(dir, 1024) != NULL) {
3520 dir[1023] = 0;
3521 ret = xmlMemStrdup(dir);
3522 }
3523 }
3524 return(ret);
3525}
3526
3527/****************************************************************
3528 * *
3529 * External entities loading *
3530 * *
3531 ****************************************************************/
3532
Daniel Veillarda840b692003-10-19 13:35:37 +00003533/**
3534 * xmlCheckHTTPInput:
3535 * @ctxt: an XML parser context
3536 * @ret: an XML parser input
3537 *
3538 * Check an input in case it was created from an HTTP stream, in that
3539 * case it will handle encoding and update of the base URL in case of
3540 * redirection. It also checks for HTTP errors in which case the input
3541 * is cleanly freed up and an appropriate error is raised in context
3542 *
3543 * Returns the input or NULL in case of HTTP error.
3544 */
3545xmlParserInputPtr
3546xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3547#ifdef LIBXML_HTTP_ENABLED
3548 if ((ret != NULL) && (ret->buf != NULL) &&
3549 (ret->buf->readcallback == xmlIOHTTPRead) &&
3550 (ret->buf->context != NULL)) {
3551 const char *encoding;
3552 const char *redir;
3553 const char *mime;
3554 int code;
3555
3556 code = xmlNanoHTTPReturnCode(ret->buf->context);
3557 if (code >= 400) {
3558 /* fatal error */
3559 if (ret->filename != NULL)
Daniel Veillarde8039df2003-10-27 11:25:13 +00003560 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
Daniel Veillarda840b692003-10-19 13:35:37 +00003561 (const char *) ret->filename);
3562 else
Daniel Veillarde8039df2003-10-27 11:25:13 +00003563 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
Daniel Veillarda840b692003-10-19 13:35:37 +00003564 xmlFreeInputStream(ret);
3565 ret = NULL;
3566 } else {
3567
3568 mime = xmlNanoHTTPMimeType(ret->buf->context);
3569 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3570 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3571 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3572 if (encoding != NULL) {
3573 xmlCharEncodingHandlerPtr handler;
3574
3575 handler = xmlFindCharEncodingHandler(encoding);
3576 if (handler != NULL) {
3577 xmlSwitchInputEncoding(ctxt, ret, handler);
3578 } else {
3579 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3580 "Unknown encoding %s",
3581 BAD_CAST encoding, NULL);
3582 }
3583 if (ret->encoding == NULL)
3584 ret->encoding = xmlStrdup(BAD_CAST encoding);
3585 }
3586#if 0
3587 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3588#endif
3589 }
3590 redir = xmlNanoHTTPRedir(ret->buf->context);
3591 if (redir != NULL) {
3592 if (ret->filename != NULL)
3593 xmlFree((xmlChar *) ret->filename);
3594 if (ret->directory != NULL) {
3595 xmlFree((xmlChar *) ret->directory);
3596 ret->directory = NULL;
3597 }
3598 ret->filename =
3599 (char *) xmlStrdup((const xmlChar *) redir);
3600 }
3601 }
3602 }
3603#endif
3604 return(ret);
3605}
3606
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003607static int xmlNoNetExists(const char *URL) {
Daniel Veillard6990bf32001-08-23 21:17:48 +00003608 const char *path;
3609
3610 if (URL == NULL)
3611 return(0);
3612
Daniel Veillardf4862f02002-09-10 11:13:43 +00003613 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003614#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillardf4862f02002-09-10 11:13:43 +00003615 path = &URL[17];
3616#else
Daniel Veillard6990bf32001-08-23 21:17:48 +00003617 path = &URL[16];
Daniel Veillardf4862f02002-09-10 11:13:43 +00003618#endif
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003619 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
Daniel Veillard1997c3e2003-07-05 20:43:43 +00003620#if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
Daniel Veillard6990bf32001-08-23 21:17:48 +00003621 path = &URL[8];
3622#else
3623 path = &URL[7];
3624#endif
3625 } else
3626 path = URL;
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003627
3628 return xmlCheckFilename(path);
Daniel Veillard6990bf32001-08-23 21:17:48 +00003629}
Daniel Veillard6990bf32001-08-23 21:17:48 +00003630
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003631/**
Owen Taylor3473f882001-02-23 17:55:21 +00003632 * xmlDefaultExternalEntityLoader:
3633 * @URL: the URL for the entity to load
3634 * @ID: the System ID for the entity to load
3635 * @ctxt: the context in which the entity is called or NULL
3636 *
3637 * By default we don't load external entitites, yet.
3638 *
3639 * Returns a new allocated xmlParserInputPtr, or NULL.
3640 */
Daniel Veillarda840b692003-10-19 13:35:37 +00003641static xmlParserInputPtr
Owen Taylor3473f882001-02-23 17:55:21 +00003642xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
Daniel Veillarda840b692003-10-19 13:35:37 +00003643 xmlParserCtxtPtr ctxt)
3644{
Owen Taylor3473f882001-02-23 17:55:21 +00003645 xmlParserInputPtr ret = NULL;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003646 xmlChar *resource = NULL;
Daniel Veillarda840b692003-10-19 13:35:37 +00003647
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003648#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003649 xmlCatalogAllow pref;
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003650#endif
Owen Taylor3473f882001-02-23 17:55:21 +00003651
3652#ifdef DEBUG_EXTERNAL_ENTITIES
3653 xmlGenericError(xmlGenericErrorContext,
Daniel Veillarda840b692003-10-19 13:35:37 +00003654 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
Owen Taylor3473f882001-02-23 17:55:21 +00003655#endif
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003656#ifdef LIBXML_CATALOG_ENABLED
Daniel Veillard61b93382003-11-03 14:28:31 +00003657 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3658 int options = ctxt->options;
3659
3660 ctxt->options -= XML_PARSE_NONET;
3661 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3662 ctxt->options = options;
3663 return(ret);
3664 }
3665
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003666 /*
Daniel Veillarde2940dd2001-08-22 00:06:49 +00003667 * If the resource doesn't exists as a file,
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003668 * try to load it from the resource pointed in the catalogs
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003669 */
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003670 pref = xmlCatalogGetDefaults();
3671
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003672 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003673 /*
3674 * Do a local lookup
3675 */
Daniel Veillard42595322004-11-08 10:52:06 +00003676 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003677 ((pref == XML_CATA_ALLOW_ALL) ||
3678 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3679 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3680 (const xmlChar *) ID,
3681 (const xmlChar *) URL);
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003682 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003683 /*
3684 * Try a global lookup
3685 */
3686 if ((resource == NULL) &&
3687 ((pref == XML_CATA_ALLOW_ALL) ||
3688 (pref == XML_CATA_ALLOW_GLOBAL))) {
3689 resource = xmlCatalogResolve((const xmlChar *) ID,
3690 (const xmlChar *) URL);
3691 }
3692 if ((resource == NULL) && (URL != NULL))
3693 resource = xmlStrdup((const xmlChar *) URL);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003694
Daniel Veillarda840b692003-10-19 13:35:37 +00003695 /*
3696 * TODO: do an URI lookup on the reference
3697 */
3698 if ((resource != NULL)
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003699 && (!xmlNoNetExists((const char *) resource))) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003700 xmlChar *tmp = NULL;
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003701
Daniel Veillard42595322004-11-08 10:52:06 +00003702 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillarda840b692003-10-19 13:35:37 +00003703 ((pref == XML_CATA_ALLOW_ALL) ||
3704 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3705 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3706 }
3707 if ((tmp == NULL) &&
3708 ((pref == XML_CATA_ALLOW_ALL) ||
3709 (pref == XML_CATA_ALLOW_GLOBAL))) {
3710 tmp = xmlCatalogResolveURI(resource);
3711 }
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003712
Daniel Veillarda840b692003-10-19 13:35:37 +00003713 if (tmp != NULL) {
3714 xmlFree(resource);
3715 resource = tmp;
3716 }
3717 }
Daniel Veillard5d90b6c2001-08-22 14:29:45 +00003718 }
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003719#endif
3720
3721 if (resource == NULL)
Daniel Veillarda840b692003-10-19 13:35:37 +00003722 resource = (xmlChar *) URL;
Daniel Veillard7d6fd212001-05-10 15:34:11 +00003723
3724 if (resource == NULL) {
Daniel Veillarda840b692003-10-19 13:35:37 +00003725 if (ID == NULL)
3726 ID = "NULL";
Daniel Veillarde8039df2003-10-27 11:25:13 +00003727 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
Daniel Veillarda840b692003-10-19 13:35:37 +00003728 return (NULL);
Owen Taylor3473f882001-02-23 17:55:21 +00003729 }
Daniel Veillarda840b692003-10-19 13:35:37 +00003730 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
Daniel Veillarddc2cee22001-08-22 16:30:37 +00003731 if ((resource != NULL) && (resource != (xmlChar *) URL))
Daniel Veillarda840b692003-10-19 13:35:37 +00003732 xmlFree(resource);
3733 return (ret);
Owen Taylor3473f882001-02-23 17:55:21 +00003734}
3735
3736static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
3737 xmlDefaultExternalEntityLoader;
3738
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003739/**
Owen Taylor3473f882001-02-23 17:55:21 +00003740 * xmlSetExternalEntityLoader:
3741 * @f: the new entity resolver function
3742 *
3743 * Changes the defaultexternal entity resolver function for the application
3744 */
3745void
3746xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3747 xmlCurrentExternalEntityLoader = f;
3748}
3749
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003750/**
Owen Taylor3473f882001-02-23 17:55:21 +00003751 * xmlGetExternalEntityLoader:
3752 *
3753 * Get the default external entity resolver function for the application
3754 *
3755 * Returns the xmlExternalEntityLoader function pointer
3756 */
3757xmlExternalEntityLoader
3758xmlGetExternalEntityLoader(void) {
3759 return(xmlCurrentExternalEntityLoader);
3760}
3761
Daniel Veillard5e2dace2001-07-18 19:30:27 +00003762/**
Owen Taylor3473f882001-02-23 17:55:21 +00003763 * xmlLoadExternalEntity:
3764 * @URL: the URL for the entity to load
Daniel Veillard9f7b84b2001-08-23 15:31:19 +00003765 * @ID: the Public ID for the entity to load
Owen Taylor3473f882001-02-23 17:55:21 +00003766 * @ctxt: the context in which the entity is called or NULL
3767 *
3768 * Load an external entity, note that the use of this function for
3769 * unparsed entities may generate problems
Owen Taylor3473f882001-02-23 17:55:21 +00003770 *
3771 * Returns the xmlParserInputPtr or NULL
3772 */
3773xmlParserInputPtr
3774xmlLoadExternalEntity(const char *URL, const char *ID,
3775 xmlParserCtxtPtr ctxt) {
Daniel Veillarde5a3f372006-08-30 13:11:36 +00003776 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003777 char *canonicFilename;
3778 xmlParserInputPtr ret;
3779
3780 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
3781 if (canonicFilename == NULL) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003782 xmlIOErrMemory("building canonical path\n");
Daniel Veillard4e9b1bc2003-06-09 10:30:33 +00003783 return(NULL);
3784 }
3785
3786 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
3787 xmlFree(canonicFilename);
3788 return(ret);
3789 }
Owen Taylor3473f882001-02-23 17:55:21 +00003790 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
3791}
3792
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003793/************************************************************************
3794 * *
3795 * Disabling Network access *
3796 * *
3797 ************************************************************************/
3798
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003799/**
3800 * xmlNoNetExternalEntityLoader:
3801 * @URL: the URL for the entity to load
3802 * @ID: the System ID for the entity to load
3803 * @ctxt: the context in which the entity is called or NULL
3804 *
3805 * A specific entity loader disabling network accesses, though still
3806 * allowing local catalog accesses for resolution.
3807 *
3808 * Returns a new allocated xmlParserInputPtr, or NULL.
3809 */
3810xmlParserInputPtr
3811xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
3812 xmlParserCtxtPtr ctxt) {
3813 xmlParserInputPtr input = NULL;
3814 xmlChar *resource = NULL;
3815
3816#ifdef LIBXML_CATALOG_ENABLED
3817 xmlCatalogAllow pref;
3818
3819 /*
3820 * If the resource doesn't exists as a file,
3821 * try to load it from the resource pointed in the catalogs
3822 */
3823 pref = xmlCatalogGetDefaults();
3824
3825 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3826 /*
3827 * Do a local lookup
3828 */
Daniel Veillard42595322004-11-08 10:52:06 +00003829 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003830 ((pref == XML_CATA_ALLOW_ALL) ||
3831 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3832 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3833 (const xmlChar *)ID,
3834 (const xmlChar *)URL);
3835 }
3836 /*
3837 * Try a global lookup
3838 */
3839 if ((resource == NULL) &&
3840 ((pref == XML_CATA_ALLOW_ALL) ||
3841 (pref == XML_CATA_ALLOW_GLOBAL))) {
3842 resource = xmlCatalogResolve((const xmlChar *)ID,
3843 (const xmlChar *)URL);
3844 }
3845 if ((resource == NULL) && (URL != NULL))
3846 resource = xmlStrdup((const xmlChar *) URL);
3847
3848 /*
3849 * TODO: do an URI lookup on the reference
3850 */
3851 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3852 xmlChar *tmp = NULL;
3853
Daniel Veillard42595322004-11-08 10:52:06 +00003854 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003855 ((pref == XML_CATA_ALLOW_ALL) ||
3856 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3857 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3858 }
3859 if ((tmp == NULL) &&
3860 ((pref == XML_CATA_ALLOW_ALL) ||
3861 (pref == XML_CATA_ALLOW_GLOBAL))) {
3862 tmp = xmlCatalogResolveURI(resource);
3863 }
3864
3865 if (tmp != NULL) {
3866 xmlFree(resource);
3867 resource = tmp;
3868 }
3869 }
3870 }
3871#endif
3872 if (resource == NULL)
3873 resource = (xmlChar *) URL;
3874
3875 if (resource != NULL) {
Aleksey Sanin5aac8b82002-05-01 18:32:28 +00003876 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
3877 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
Daniel Veillard05d987b2003-10-08 11:54:57 +00003878 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
Daniel Veillard8bdb91d2001-10-31 17:52:43 +00003879 if (resource != (xmlChar *) URL)
3880 xmlFree(resource);
3881 return(NULL);
3882 }
3883 }
3884 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
3885 if (resource != (xmlChar *) URL)
3886 xmlFree(resource);
3887 return(input);
3888}
3889
Daniel Veillard5d4644e2005-04-01 13:11:58 +00003890#define bottom_xmlIO
3891#include "elfgcchack.h"