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