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