Coverage Report

Created: 2024-02-11 06:20

/src/libxml2-2.12.5/xmlIO.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * xmlIO.c : implementation of the I/O interfaces used by the parser
3
 *
4
 * See Copyright for the status of this software.
5
 *
6
 * daniel@veillard.com
7
 *
8
 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9
 */
10
11
#define IN_LIBXML
12
#include "libxml.h"
13
14
#include <string.h>
15
#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
0
#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
2
#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
2
#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
0
{
217
0
    __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
218
0
}
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
0
{
232
0
    unsigned int idx;
233
234
0
    if (code == 0) {
235
0
  if (errno == 0) code = 0;
236
0
#ifdef EACCES
237
0
        else if (errno == EACCES) code = XML_IO_EACCES;
238
0
#endif
239
0
#ifdef EAGAIN
240
0
        else if (errno == EAGAIN) code = XML_IO_EAGAIN;
241
0
#endif
242
0
#ifdef EBADF
243
0
        else if (errno == EBADF) code = XML_IO_EBADF;
244
0
#endif
245
0
#ifdef EBADMSG
246
0
        else if (errno == EBADMSG) code = XML_IO_EBADMSG;
247
0
#endif
248
0
#ifdef EBUSY
249
0
        else if (errno == EBUSY) code = XML_IO_EBUSY;
250
0
#endif
251
0
#ifdef ECANCELED
252
0
        else if (errno == ECANCELED) code = XML_IO_ECANCELED;
253
0
#endif
254
0
#ifdef ECHILD
255
0
        else if (errno == ECHILD) code = XML_IO_ECHILD;
256
0
#endif
257
0
#ifdef EDEADLK
258
0
        else if (errno == EDEADLK) code = XML_IO_EDEADLK;
259
0
#endif
260
0
#ifdef EDOM
261
0
        else if (errno == EDOM) code = XML_IO_EDOM;
262
0
#endif
263
0
#ifdef EEXIST
264
0
        else if (errno == EEXIST) code = XML_IO_EEXIST;
265
0
#endif
266
0
#ifdef EFAULT
267
0
        else if (errno == EFAULT) code = XML_IO_EFAULT;
268
0
#endif
269
0
#ifdef EFBIG
270
0
        else if (errno == EFBIG) code = XML_IO_EFBIG;
271
0
#endif
272
0
#ifdef EINPROGRESS
273
0
        else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
274
0
#endif
275
0
#ifdef EINTR
276
0
        else if (errno == EINTR) code = XML_IO_EINTR;
277
0
#endif
278
0
#ifdef EINVAL
279
0
        else if (errno == EINVAL) code = XML_IO_EINVAL;
280
0
#endif
281
0
#ifdef EIO
282
0
        else if (errno == EIO) code = XML_IO_EIO;
283
0
#endif
284
0
#ifdef EISDIR
285
0
        else if (errno == EISDIR) code = XML_IO_EISDIR;
286
0
#endif
287
0
#ifdef EMFILE
288
0
        else if (errno == EMFILE) code = XML_IO_EMFILE;
289
0
#endif
290
0
#ifdef EMLINK
291
0
        else if (errno == EMLINK) code = XML_IO_EMLINK;
292
0
#endif
293
0
#ifdef EMSGSIZE
294
0
        else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
295
0
#endif
296
0
#ifdef ENAMETOOLONG
297
0
        else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
298
0
#endif
299
0
#ifdef ENFILE
300
0
        else if (errno == ENFILE) code = XML_IO_ENFILE;
301
0
#endif
302
0
#ifdef ENODEV
303
0
        else if (errno == ENODEV) code = XML_IO_ENODEV;
304
0
#endif
305
0
#ifdef ENOENT
306
0
        else if (errno == ENOENT) code = XML_IO_ENOENT;
307
0
#endif
308
0
#ifdef ENOEXEC
309
0
        else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
310
0
#endif
311
0
#ifdef ENOLCK
312
0
        else if (errno == ENOLCK) code = XML_IO_ENOLCK;
313
0
#endif
314
0
#ifdef ENOMEM
315
0
        else if (errno == ENOMEM) code = XML_IO_ENOMEM;
316
0
#endif
317
0
#ifdef ENOSPC
318
0
        else if (errno == ENOSPC) code = XML_IO_ENOSPC;
319
0
#endif
320
0
#ifdef ENOSYS
321
0
        else if (errno == ENOSYS) code = XML_IO_ENOSYS;
322
0
#endif
323
0
#ifdef ENOTDIR
324
0
        else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
325
0
#endif
326
0
#ifdef ENOTEMPTY
327
0
        else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
328
0
#endif
329
0
#ifdef ENOTSUP
330
0
        else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
331
0
#endif
332
0
#ifdef ENOTTY
333
0
        else if (errno == ENOTTY) code = XML_IO_ENOTTY;
334
0
#endif
335
0
#ifdef ENXIO
336
0
        else if (errno == ENXIO) code = XML_IO_ENXIO;
337
0
#endif
338
0
#ifdef EPERM
339
0
        else if (errno == EPERM) code = XML_IO_EPERM;
340
0
#endif
341
0
#ifdef EPIPE
342
0
        else if (errno == EPIPE) code = XML_IO_EPIPE;
343
0
#endif
344
0
#ifdef ERANGE
345
0
        else if (errno == ERANGE) code = XML_IO_ERANGE;
346
0
#endif
347
0
#ifdef EROFS
348
0
        else if (errno == EROFS) code = XML_IO_EROFS;
349
0
#endif
350
0
#ifdef ESPIPE
351
0
        else if (errno == ESPIPE) code = XML_IO_ESPIPE;
352
0
#endif
353
0
#ifdef ESRCH
354
0
        else if (errno == ESRCH) code = XML_IO_ESRCH;
355
0
#endif
356
0
#ifdef ETIMEDOUT
357
0
        else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
358
0
#endif
359
0
#ifdef EXDEV
360
0
        else if (errno == EXDEV) code = XML_IO_EXDEV;
361
0
#endif
362
0
#ifdef ENOTSOCK
363
0
        else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
364
0
#endif
365
0
#ifdef EISCONN
366
0
        else if (errno == EISCONN) code = XML_IO_EISCONN;
367
0
#endif
368
0
#ifdef ECONNREFUSED
369
0
        else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
370
0
#endif
371
0
#ifdef ETIMEDOUT
372
0
        else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
373
0
#endif
374
0
#ifdef ENETUNREACH
375
0
        else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
376
0
#endif
377
0
#ifdef EADDRINUSE
378
0
        else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
379
0
#endif
380
0
#ifdef EINPROGRESS
381
0
        else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
382
0
#endif
383
0
#ifdef EALREADY
384
0
        else if (errno == EALREADY) code = XML_IO_EALREADY;
385
0
#endif
386
0
#ifdef EAFNOSUPPORT
387
0
        else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
388
0
#endif
389
0
        else code = XML_IO_UNKNOWN;
390
0
    }
391
0
    idx = 0;
392
0
    if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
393
0
    if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
394
395
0
    __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
396
0
}
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
0
{
408
0
    __xmlIOErr(XML_FROM_IO, code, extra);
409
0
}
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
0
{
421
0
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
422
0
    xmlStructuredErrorFunc schannel = NULL;
423
0
    xmlGenericErrorFunc channel = NULL;
424
0
    void *data = NULL;
425
0
    xmlErrorLevel level = XML_ERR_ERROR;
426
427
0
    if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
428
0
        (ctxt->instate == XML_PARSER_EOF))
429
0
  return;
430
0
    if ((ctxt != NULL) && (ctxt->sax != NULL)) {
431
0
        if (ctxt->validate) {
432
0
      channel = ctxt->sax->error;
433
0
      level = XML_ERR_ERROR;
434
0
  } else {
435
0
      channel = ctxt->sax->warning;
436
0
      level = XML_ERR_WARNING;
437
0
  }
438
0
  if (ctxt->sax->initialized == XML_SAX2_MAGIC)
439
0
      schannel = ctxt->sax->serror;
440
0
  data = ctxt->userData;
441
0
    }
442
0
    __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
443
0
                    XML_IO_LOAD_ERROR, level, NULL, 0,
444
0
        filename, NULL, NULL, 0, 0,
445
0
        msg, filename);
446
447
0
}
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
0
{
466
0
    return xmlCanonicPath(path);
467
0
}
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
0
{
478
0
    int i;
479
480
0
    if (!xmlInputCallbackInitialized)
481
0
        return;
482
483
0
    for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
484
0
        xmlInputCallbackTable[i].matchcallback = NULL;
485
0
        xmlInputCallbackTable[i].opencallback = NULL;
486
0
        xmlInputCallbackTable[i].readcallback = NULL;
487
0
        xmlInputCallbackTable[i].closecallback = NULL;
488
0
    }
489
490
0
    xmlInputCallbackNr = 0;
491
0
    xmlInputCallbackInitialized = 0;
492
0
}
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
0
{
505
0
    if (!xmlInputCallbackInitialized)
506
0
        return(-1);
507
508
0
    if (xmlInputCallbackNr <= 0)
509
0
        return(-1);
510
511
0
    xmlInputCallbackNr--;
512
0
    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
513
0
    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
514
0
    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
515
0
    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
516
517
0
    return(xmlInputCallbackNr);
518
0
}
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
0
{
530
0
    int i;
531
532
0
    if (!xmlOutputCallbackInitialized)
533
0
        return;
534
535
0
    for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
536
0
        xmlOutputCallbackTable[i].matchcallback = NULL;
537
0
        xmlOutputCallbackTable[i].opencallback = NULL;
538
0
        xmlOutputCallbackTable[i].writecallback = NULL;
539
0
        xmlOutputCallbackTable[i].closecallback = NULL;
540
0
    }
541
542
0
    xmlOutputCallbackNr = 0;
543
0
    xmlOutputCallbackInitialized = 0;
544
0
}
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
0
{
557
0
    if (!xmlOutputCallbackInitialized)
558
0
        return(-1);
559
560
0
    if (xmlOutputCallbackNr <= 0)
561
0
        return(-1);
562
563
0
    xmlOutputCallbackNr--;
564
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = NULL;
565
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = NULL;
566
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = NULL;
567
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = NULL;
568
569
0
    return(xmlOutputCallbackNr);
570
0
}
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
0
{
680
0
#ifdef HAVE_STAT
681
#if defined(_WIN32)
682
    struct _stat stat_buffer;
683
#else
684
0
    struct stat stat_buffer;
685
0
#endif
686
0
#endif
687
0
    if (path == NULL)
688
0
  return(0);
689
690
0
#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
0
    if (stat(path, &stat_buffer) == -1)
704
0
        return 0;
705
0
#endif
706
0
#ifdef S_ISDIR
707
0
    if (S_ISDIR(stat_buffer.st_mode))
708
0
        return 2;
709
0
#endif
710
0
#endif /* HAVE_STAT */
711
0
    return 1;
712
0
}
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
0
xmlFdRead (void * context, char * buffer, int len) {
726
0
    int ret;
727
728
0
    ret = read((int) (ptrdiff_t) context, &buffer[0], len);
729
0
    if (ret < 0) xmlIOErr(0, "read()");
730
0
    return(ret);
731
0
}
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
0
xmlFdWrite (void * context, const char * buffer, int len) {
746
0
    int ret = 0;
747
748
0
    if (len > 0) {
749
0
  ret = write((int) (ptrdiff_t) context, &buffer[0], len);
750
0
  if (ret < 0) xmlIOErr(0, "write()");
751
0
    }
752
0
    return(ret);
753
0
}
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
0
xmlFdClose (void * context) {
766
0
    int ret;
767
0
    ret = close((int) (ptrdiff_t) context);
768
0
    if (ret < 0) xmlIOErr(0, "close()");
769
0
    return(ret);
770
0
}
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
0
xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
782
0
    return(1);
783
0
}
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
0
xmlFileOpen_real (const char *filename) {
796
0
    const char *path = filename;
797
0
    FILE *fd;
798
799
0
    if (filename == NULL)
800
0
        return(NULL);
801
802
0
    if (!strcmp(filename, "-")) {
803
0
  fd = stdin;
804
0
  return((void *) fd);
805
0
    }
806
807
0
    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
808
#if defined (_WIN32)
809
  path = &filename[17];
810
#else
811
0
  path = &filename[16];
812
0
#endif
813
0
    } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
814
#if defined (_WIN32)
815
  path = &filename[8];
816
#else
817
0
  path = &filename[7];
818
0
#endif
819
0
    } 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
0
  path = &filename[5];
825
0
#endif
826
0
    }
827
828
    /* Do not check DDNAME on zOS ! */
829
0
#if !defined(__MVS__)
830
0
    if (!xmlCheckFilename(path))
831
0
        return(NULL);
832
0
#endif
833
834
#if defined(_WIN32)
835
    fd = xmlWrapOpenUtf8(path, 0);
836
#else
837
0
    fd = fopen(path, "rb");
838
0
#endif /* WIN32 */
839
0
    if (fd == NULL) xmlIOErr(0, path);
840
0
    return((void *) fd);
841
0
}
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
0
xmlFileOpen (const char *filename) {
854
0
    char *unescaped;
855
0
    void *retval;
856
857
0
    retval = xmlFileOpen_real(filename);
858
0
    if (retval == NULL) {
859
0
  unescaped = xmlURIUnescapeString(filename, 0, NULL);
860
0
  if (unescaped != NULL) {
861
0
      retval = xmlFileOpen_real(unescaped);
862
0
      xmlFree(unescaped);
863
0
  }
864
0
    }
865
866
0
    return retval;
867
0
}
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
0
xmlFileOpenW (const char *filename) {
881
0
    const char *path = NULL;
882
0
    FILE *fd;
883
884
0
    if (!strcmp(filename, "-")) {
885
0
  fd = stdout;
886
0
  return((void *) fd);
887
0
    }
888
889
0
    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
890
#if defined (_WIN32)
891
  path = &filename[17];
892
#else
893
0
  path = &filename[16];
894
0
#endif
895
0
    else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
896
#if defined (_WIN32)
897
  path = &filename[8];
898
#else
899
0
  path = &filename[7];
900
0
#endif
901
0
    } else
902
0
  path = filename;
903
904
0
    if (path == NULL)
905
0
  return(NULL);
906
907
#if defined(_WIN32)
908
    fd = xmlWrapOpenUtf8(path, 1);
909
#elif(__MVS__)
910
    fd = fopen(path, "w");
911
#else
912
0
    fd = fopen(path, "wb");
913
0
#endif /* WIN32 */
914
915
0
    if (fd == NULL) xmlIOErr(0, path);
916
0
    return((void *) fd);
917
0
}
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
0
xmlFileRead (void * context, char * buffer, int len) {
932
0
    int ret;
933
0
    if ((context == NULL) || (buffer == NULL))
934
0
        return(-1);
935
0
    ret = fread(&buffer[0], 1,  len, (FILE *) context);
936
0
    if (ret < 0) xmlIOErr(0, "fread()");
937
0
    return(ret);
938
0
}
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
0
xmlFileWrite (void * context, const char * buffer, int len) {
953
0
    int items;
954
955
0
    if ((context == NULL) || (buffer == NULL))
956
0
        return(-1);
957
0
    items = fwrite(&buffer[0], len, 1, (FILE *) context);
958
0
    if ((items == 0) && (ferror((FILE *) context))) {
959
0
        xmlIOErr(0, "fwrite()");
960
0
  return(-1);
961
0
    }
962
0
    return(items * len);
963
0
}
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
0
xmlFileClose (void * context) {
976
0
    FILE *fil;
977
0
    int ret;
978
979
0
    if (context == NULL)
980
0
        return(-1);
981
0
    fil = (FILE *) context;
982
0
    if ((fil == stdout) || (fil == stderr)) {
983
0
        ret = fflush(fil);
984
0
  if (ret < 0)
985
0
      xmlIOErr(0, "fflush()");
986
0
  return(0);
987
0
    }
988
0
    if (fil == stdin)
989
0
  return(0);
990
0
    ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
991
0
    if (ret < 0)
992
0
        xmlIOErr(0, "fclose()");
993
0
    return(ret);
994
0
}
995
996
/**
997
 * xmlFileFlush:
998
 * @context:  the I/O context
999
 *
1000
 * Flush an I/O channel
1001
 */
1002
static int
1003
0
xmlFileFlush (void * context) {
1004
0
    int ret;
1005
1006
0
    if (context == NULL)
1007
0
        return(-1);
1008
0
    ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1009
0
    if (ret < 0)
1010
0
        xmlIOErr(0, "fflush()");
1011
0
    return(ret);
1012
0
}
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
0
xmlBufferWrite (void * context, const char * buffer, int len) {
1027
0
    int ret;
1028
1029
0
    ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1030
0
    if (ret != 0)
1031
0
        return(-1);
1032
0
    return(len);
1033
0
}
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
0
{
1699
0
    if ( ctxt->uri != NULL )
1700
0
  xmlFree( ctxt->uri );
1701
1702
0
    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
0
  {
1711
0
      xmlOutputBufferClose( ctxt->doc_buff );
1712
0
  }
1713
0
    }
1714
1715
0
    xmlFree( ctxt );
1716
0
    return;
1717
0
}
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
0
xmlIOHTTPMatch (const char *filename) {
1731
0
    if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
1732
0
  return(1);
1733
0
    return(0);
1734
0
}
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
0
xmlIOHTTPOpen (const char *filename) {
1746
0
    return(xmlNanoHTTPOpen(filename, NULL));
1747
0
}
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
0
{
1764
1765
0
    xmlIOHTTPWriteCtxtPtr ctxt = NULL;
1766
1767
0
    if (post_uri == NULL)
1768
0
        return (NULL);
1769
1770
0
    ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1771
0
    if (ctxt == NULL) {
1772
0
  xmlIOErrMemory("creating HTTP output context");
1773
0
        return (NULL);
1774
0
    }
1775
1776
0
    (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
1777
1778
0
    ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1779
0
    if (ctxt->uri == NULL) {
1780
0
  xmlIOErrMemory("copying URI");
1781
0
        xmlFreeHTTPWriteCtxt(ctxt);
1782
0
        return (NULL);
1783
0
    }
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
0
    {
1799
        /*  Any character conversions should have been done before this  */
1800
1801
0
        ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
1802
0
    }
1803
1804
0
    if (ctxt->doc_buff == NULL) {
1805
0
        xmlFreeHTTPWriteCtxt(ctxt);
1806
0
        ctxt = NULL;
1807
0
    }
1808
1809
0
    return (ctxt);
1810
0
}
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
0
xmlIOHTTPDfltOpenW( const char * post_uri ) {
1826
0
    return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1827
0
}
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
0
xmlIOHTTPRead(void * context, char * buffer, int len) {
1842
0
    if ((buffer == NULL) || (len < 0)) return(-1);
1843
0
    return(xmlNanoHTTPRead(context, &buffer[0], len));
1844
0
}
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
0
xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1861
1862
0
    xmlIOHTTPWriteCtxtPtr ctxt = context;
1863
1864
0
    if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1865
0
  return ( -1 );
1866
1867
0
    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
0
      len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1878
1879
0
  if ( len < 0 ) {
1880
0
      xmlChar msg[500];
1881
0
      xmlStrPrintf(msg, 500,
1882
0
      "xmlIOHTTPWrite:  %s\n%s '%s'.\n",
1883
0
      "Error appending to internal buffer.",
1884
0
      "Error sending document to URI",
1885
0
      ctxt->uri );
1886
0
      xmlIOErr(XML_IO_WRITE, (const char *) msg);
1887
0
  }
1888
0
    }
1889
1890
0
    return ( len );
1891
0
}
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
0
xmlIOHTTPClose (void * context) {
1905
0
    xmlNanoHTTPClose(context);
1906
0
    return 0;
1907
0
}
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
0
xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
1919
1920
0
    int       close_rc = -1;
1921
0
    int       http_rtn = 0;
1922
0
    int       content_lgth = 0;
1923
0
    xmlIOHTTPWriteCtxtPtr ctxt = context;
1924
1925
0
    char *      http_content = NULL;
1926
0
    char *      content_encoding = NULL;
1927
0
    char *      content_type = (char *) "text/xml";
1928
0
    void *      http_ctxt = NULL;
1929
1930
0
    if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
1931
0
  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
0
    {
1944
  /*  Pull the data out of the memory output buffer  */
1945
1946
0
  xmlOutputBufferPtr  dctxt = ctxt->doc_buff;
1947
0
  http_content = (char *) xmlBufContent(dctxt->buffer);
1948
0
  content_lgth = xmlBufUse(dctxt->buffer);
1949
0
    }
1950
1951
0
    if ( http_content == NULL ) {
1952
0
  xmlChar msg[500];
1953
0
  xmlStrPrintf(msg, 500,
1954
0
         "xmlIOHTTPCloseWrite:  %s '%s' %s '%s'.\n",
1955
0
         "Error retrieving content.\nUnable to",
1956
0
         http_mthd, "data to URI", ctxt->uri );
1957
0
  xmlIOErr(XML_IO_WRITE, (const char *) msg);
1958
0
    }
1959
1960
0
    else {
1961
1962
0
  http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
1963
0
          &content_type, content_encoding,
1964
0
          content_lgth );
1965
1966
0
  if ( http_ctxt != NULL ) {
1967
1968
0
      http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
1969
0
      if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
1970
0
    close_rc = 0;
1971
0
      else {
1972
0
                xmlChar msg[500];
1973
0
                xmlStrPrintf(msg, 500,
1974
0
                      "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
1975
0
          http_mthd, content_lgth,
1976
0
          "bytes to URI", ctxt->uri,
1977
0
          "failed.  HTTP return code:", http_rtn );
1978
0
    xmlIOErr(XML_IO_WRITE, (const char *) msg);
1979
0
            }
1980
1981
0
      xmlNanoHTTPClose( http_ctxt );
1982
0
      xmlFree( content_type );
1983
0
  }
1984
0
    }
1985
1986
    /*  Final cleanups  */
1987
1988
0
    xmlFreeHTTPWriteCtxt( ctxt );
1989
1990
0
    return ( close_rc );
1991
0
}
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
0
xmlIOHTTPClosePut( void * ctxt ) {
2003
0
    return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2004
0
}
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
0
xmlIOHTTPClosePost( void * ctxt ) {
2017
0
    return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2018
0
}
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
2
  xmlInputCloseCallback closeFunc) {
2103
2
    if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2104
0
  return(-1);
2105
0
    }
2106
2
    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2107
2
    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2108
2
    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2109
2
    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
2110
2
    xmlInputCallbackInitialized = 1;
2111
2
    return(xmlInputCallbackNr++);
2112
2
}
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
2
  xmlOutputCloseCallback closeFunc) {
2130
2
    if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
2131
0
  return(-1);
2132
0
    }
2133
2
    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2134
2
    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2135
2
    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2136
2
    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
2137
2
    xmlOutputCallbackInitialized = 1;
2138
2
    return(xmlOutputCallbackNr++);
2139
2
}
2140
#endif /* LIBXML_OUTPUT_ENABLED */
2141
2142
/**
2143
 * xmlRegisterDefaultInputCallbacks:
2144
 *
2145
 * Registers the default compiled-in I/O handlers.
2146
 */
2147
void
2148
1
xmlRegisterDefaultInputCallbacks(void) {
2149
1
    if (xmlInputCallbackInitialized)
2150
0
  return;
2151
2152
1
    xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2153
1
                        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
1
#ifdef LIBXML_HTTP_ENABLED
2164
1
    xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2165
1
                        xmlIOHTTPRead, xmlIOHTTPClose);
2166
1
#endif /* LIBXML_HTTP_ENABLED */
2167
2168
#ifdef LIBXML_FTP_ENABLED
2169
    xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2170
                        xmlIOFTPRead, xmlIOFTPClose);
2171
#endif /* LIBXML_FTP_ENABLED */
2172
1
    xmlInputCallbackInitialized = 1;
2173
1
}
2174
2175
#ifdef LIBXML_OUTPUT_ENABLED
2176
/**
2177
 * xmlRegisterDefaultOutputCallbacks:
2178
 *
2179
 * Registers the default compiled-in I/O handlers.
2180
 */
2181
void
2182
1
xmlRegisterDefaultOutputCallbacks (void) {
2183
1
    if (xmlOutputCallbackInitialized)
2184
0
  return;
2185
2186
1
    xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2187
1
                        xmlFileWrite, xmlFileClose);
2188
2189
1
#ifdef LIBXML_HTTP_ENABLED
2190
1
    xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2191
1
                         xmlIOHTTPWrite, xmlIOHTTPClosePut);
2192
1
#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
1
    xmlOutputCallbackInitialized = 1;
2211
1
}
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
0
xmlRegisterHTTPPostCallbacks( void ) {
2224
2225
    /*  Register defaults if not done previously  */
2226
2227
0
    if ( xmlOutputCallbackInitialized == 0 )
2228
0
  xmlRegisterDefaultOutputCallbacks( );
2229
2230
0
    xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2231
0
                         xmlIOHTTPWrite, xmlIOHTTPClosePost);
2232
0
    return;
2233
0
}
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
16.2k
xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2247
16.2k
    xmlParserInputBufferPtr ret;
2248
2249
16.2k
    ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2250
16.2k
    if (ret == NULL) {
2251
0
  return(NULL);
2252
0
    }
2253
16.2k
    memset(ret, 0, sizeof(xmlParserInputBuffer));
2254
16.2k
    ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2255
16.2k
    if (ret->buffer == NULL) {
2256
0
        xmlFree(ret);
2257
0
  return(NULL);
2258
0
    }
2259
16.2k
    xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2260
16.2k
    ret->encoder = xmlGetCharEncodingHandler(enc);
2261
16.2k
    if (ret->encoder != NULL)
2262
0
        ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2263
16.2k
    else
2264
16.2k
        ret->raw = NULL;
2265
16.2k
    ret->readcallback = NULL;
2266
16.2k
    ret->closecallback = NULL;
2267
16.2k
    ret->context = NULL;
2268
16.2k
    ret->compressed = -1;
2269
16.2k
    ret->rawconsumed = 0;
2270
2271
16.2k
    return(ret);
2272
16.2k
}
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
0
xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2285
0
    xmlOutputBufferPtr ret;
2286
2287
0
    ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2288
0
    if (ret == NULL) {
2289
0
  return(NULL);
2290
0
    }
2291
0
    memset(ret, 0, sizeof(xmlOutputBuffer));
2292
0
    ret->buffer = xmlBufCreate();
2293
0
    if (ret->buffer == NULL) {
2294
0
        xmlFree(ret);
2295
0
  return(NULL);
2296
0
    }
2297
0
    xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2298
2299
0
    ret->encoder = encoder;
2300
0
    if (encoder != NULL) {
2301
0
        ret->conv = xmlBufCreateSize(4000);
2302
0
  if (ret->conv == NULL) {
2303
0
            xmlBufFree(ret->buffer);
2304
0
      xmlFree(ret);
2305
0
      return(NULL);
2306
0
  }
2307
2308
  /*
2309
   * This call is designed to initiate the encoder state
2310
   */
2311
0
  xmlCharEncOutput(ret, 1);
2312
0
    } else
2313
0
        ret->conv = NULL;
2314
0
    ret->writecallback = NULL;
2315
0
    ret->closecallback = NULL;
2316
0
    ret->context = NULL;
2317
0
    ret->written = 0;
2318
2319
0
    return(ret);
2320
0
}
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
0
xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2332
0
    xmlOutputBufferPtr ret;
2333
2334
0
    ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2335
0
    if (ret == NULL) {
2336
0
  return(NULL);
2337
0
    }
2338
0
    memset(ret, 0, sizeof(xmlOutputBuffer));
2339
0
    ret->buffer = xmlBufCreate();
2340
0
    if (ret->buffer == NULL) {
2341
0
        xmlFree(ret);
2342
0
  return(NULL);
2343
0
    }
2344
2345
2346
    /*
2347
     * For conversion buffers we use the special IO handling
2348
     */
2349
0
    xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
2350
2351
0
    ret->encoder = encoder;
2352
0
    if (encoder != NULL) {
2353
0
        ret->conv = xmlBufCreateSize(4000);
2354
0
  if (ret->conv == NULL) {
2355
0
            xmlBufFree(ret->buffer);
2356
0
      xmlFree(ret);
2357
0
      return(NULL);
2358
0
  }
2359
2360
  /*
2361
   * This call is designed to initiate the encoder state
2362
   */
2363
0
        xmlCharEncOutput(ret, 1);
2364
0
    } else
2365
0
        ret->conv = NULL;
2366
0
    ret->writecallback = NULL;
2367
0
    ret->closecallback = NULL;
2368
0
    ret->context = NULL;
2369
0
    ret->written = 0;
2370
2371
0
    return(ret);
2372
0
}
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
16.2k
xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
2384
16.2k
    if (in == NULL) return;
2385
2386
16.2k
    if (in->raw) {
2387
2.57k
        xmlBufFree(in->raw);
2388
2.57k
  in->raw = NULL;
2389
2.57k
    }
2390
16.2k
    if (in->encoder != NULL) {
2391
2.57k
        xmlCharEncCloseFunc(in->encoder);
2392
2.57k
    }
2393
16.2k
    if (in->closecallback != NULL) {
2394
0
  in->closecallback(in->context);
2395
0
    }
2396
16.2k
    if (in->buffer != NULL) {
2397
16.2k
        xmlBufFree(in->buffer);
2398
16.2k
  in->buffer = NULL;
2399
16.2k
    }
2400
2401
16.2k
    xmlFree(in);
2402
16.2k
}
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
0
{
2417
0
    int written;
2418
0
    int err_rc = 0;
2419
2420
0
    if (out == NULL)
2421
0
        return (-1);
2422
0
    if (out->writecallback != NULL)
2423
0
        xmlOutputBufferFlush(out);
2424
0
    if (out->closecallback != NULL) {
2425
0
        err_rc = out->closecallback(out->context);
2426
0
    }
2427
0
    written = out->written;
2428
0
    if (out->conv) {
2429
0
        xmlBufFree(out->conv);
2430
0
        out->conv = NULL;
2431
0
    }
2432
0
    if (out->encoder != NULL) {
2433
0
        xmlCharEncCloseFunc(out->encoder);
2434
0
    }
2435
0
    if (out->buffer != NULL) {
2436
0
        xmlBufFree(out->buffer);
2437
0
        out->buffer = NULL;
2438
0
    }
2439
2440
0
    if (out->error)
2441
0
        err_rc = -1;
2442
0
    xmlFree(out);
2443
0
    return ((err_rc == 0) ? written : err_rc);
2444
0
}
2445
#endif /* LIBXML_OUTPUT_ENABLED */
2446
2447
xmlParserInputBufferPtr
2448
0
__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2449
0
    xmlParserInputBufferPtr ret;
2450
0
    int i = 0;
2451
0
    void *context = NULL;
2452
2453
0
    if (xmlInputCallbackInitialized == 0)
2454
0
  xmlRegisterDefaultInputCallbacks();
2455
2456
0
    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
0
    if (context == NULL) {
2463
0
  for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2464
0
      if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2465
0
    (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
2466
0
    context = xmlInputCallbackTable[i].opencallback(URI);
2467
0
    if (context != NULL) {
2468
0
        break;
2469
0
    }
2470
0
      }
2471
0
  }
2472
0
    }
2473
0
    if (context == NULL) {
2474
0
  return(NULL);
2475
0
    }
2476
2477
    /*
2478
     * Allocate the Input buffer front-end.
2479
     */
2480
0
    ret = xmlAllocParserInputBuffer(enc);
2481
0
    if (ret != NULL) {
2482
0
  ret->context = context;
2483
0
  ret->readcallback = xmlInputCallbackTable[i].readcallback;
2484
0
  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
0
    }
2512
0
    else
2513
0
      xmlInputCallbackTable[i].closecallback (context);
2514
2515
0
    return(ret);
2516
0
}
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
0
xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2533
0
    if ((xmlParserInputBufferCreateFilenameValue)) {
2534
0
    return xmlParserInputBufferCreateFilenameValue(URI, enc);
2535
0
  }
2536
0
  return __xmlParserInputBufferCreateFilename(URI, enc);
2537
0
}
2538
2539
#ifdef LIBXML_OUTPUT_ENABLED
2540
xmlOutputBufferPtr
2541
__xmlOutputBufferCreateFilename(const char *URI,
2542
                              xmlCharEncodingHandlerPtr encoder,
2543
0
                              int compression ATTRIBUTE_UNUSED) {
2544
0
    xmlOutputBufferPtr ret;
2545
0
    xmlURIPtr puri;
2546
0
    int i = 0;
2547
0
    void *context = NULL;
2548
0
    char *unescaped = NULL;
2549
#ifdef LIBXML_ZLIB_ENABLED
2550
    int is_file_uri = 1;
2551
#endif
2552
2553
0
    if (xmlOutputCallbackInitialized == 0)
2554
0
  xmlRegisterDefaultOutputCallbacks();
2555
2556
0
    if (URI == NULL) return(NULL);
2557
2558
0
    puri = xmlParseURI(URI);
2559
0
    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
0
  if ((puri->scheme == NULL) ||
2569
0
      (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2570
0
      unescaped = xmlURIUnescapeString(URI, 0, NULL);
2571
0
  xmlFreeURI(puri);
2572
0
    }
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
0
    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
0
  for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2596
0
      if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2597
0
    (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
0
        context = xmlOutputCallbackTable[i].opencallback(unescaped);
2605
0
    if (context != NULL)
2606
0
        break;
2607
0
      }
2608
0
  }
2609
0
  xmlFree(unescaped);
2610
0
    }
2611
2612
    /*
2613
     * If this failed try with a non-escaped URI this may be a strange
2614
     * filename
2615
     */
2616
0
    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
0
  for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2634
0
      if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2635
0
    (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
0
        context = xmlOutputCallbackTable[i].opencallback(URI);
2643
0
    if (context != NULL)
2644
0
        break;
2645
0
      }
2646
0
  }
2647
0
    }
2648
2649
0
    if (context == NULL) {
2650
0
  return(NULL);
2651
0
    }
2652
2653
    /*
2654
     * Allocate the Output buffer front-end.
2655
     */
2656
0
    ret = xmlAllocOutputBufferInternal(encoder);
2657
0
    if (ret != NULL) {
2658
0
  ret->context = context;
2659
0
  ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2660
0
  ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2661
0
    }
2662
0
    return(ret);
2663
0
}
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
0
                              int compression ATTRIBUTE_UNUSED) {
2684
0
    if ((xmlOutputBufferCreateFilenameValue)) {
2685
0
    return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2686
0
  }
2687
0
  return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2688
0
}
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
0
xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2703
0
    xmlParserInputBufferPtr ret;
2704
2705
0
    if (xmlInputCallbackInitialized == 0)
2706
0
  xmlRegisterDefaultInputCallbacks();
2707
2708
0
    if (file == NULL) return(NULL);
2709
2710
0
    ret = xmlAllocParserInputBuffer(enc);
2711
0
    if (ret != NULL) {
2712
0
        ret->context = file;
2713
0
  ret->readcallback = xmlFileRead;
2714
0
  ret->closecallback = xmlFileFlush;
2715
0
    }
2716
2717
0
    return(ret);
2718
0
}
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
0
xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2733
0
    xmlOutputBufferPtr ret;
2734
2735
0
    if (xmlOutputCallbackInitialized == 0)
2736
0
  xmlRegisterDefaultOutputCallbacks();
2737
2738
0
    if (file == NULL) return(NULL);
2739
2740
0
    ret = xmlAllocOutputBufferInternal(encoder);
2741
0
    if (ret != NULL) {
2742
0
        ret->context = file;
2743
0
  ret->writecallback = xmlFileWrite;
2744
0
  ret->closecallback = xmlFileFlush;
2745
0
    }
2746
2747
0
    return(ret);
2748
0
}
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
0
                            xmlCharEncodingHandlerPtr encoder) {
2762
0
    xmlOutputBufferPtr ret;
2763
2764
0
    if (buffer == NULL) return(NULL);
2765
2766
0
    ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
2767
0
                                  encoder);
2768
2769
0
    return(ret);
2770
0
}
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
0
xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2782
0
    if ((out == NULL) || (out->buffer == NULL))
2783
0
        return(NULL);
2784
2785
0
    return(xmlBufContent(out->buffer));
2786
0
}
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
0
xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2798
0
    if ((out == NULL) || (out->buffer == NULL))
2799
0
        return(0);
2800
2801
0
    return(xmlBufUse(out->buffer));
2802
0
}
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
0
xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2819
0
    xmlParserInputBufferPtr ret;
2820
2821
0
    if (fd < 0) return(NULL);
2822
2823
0
    ret = xmlAllocParserInputBuffer(enc);
2824
0
    if (ret != NULL) {
2825
0
        ret->context = (void *) (ptrdiff_t) fd;
2826
0
  ret->readcallback = xmlFdRead;
2827
0
  ret->closecallback = xmlFdClose;
2828
0
    }
2829
2830
0
    return(ret);
2831
0
}
2832
2833
typedef struct {
2834
    char *mem;
2835
    const char *cur;
2836
    size_t size;
2837
} xmlMemIOCtxt;
2838
2839
static int
2840
0
xmlMemRead(void *vctxt, char *buf, int size) {
2841
0
    xmlMemIOCtxt *ctxt = vctxt;
2842
2843
0
    if ((size_t) size > ctxt->size)
2844
0
        size = ctxt->size;
2845
2846
0
    memcpy(buf, ctxt->cur, size);
2847
0
    ctxt->cur += size;
2848
0
    ctxt->size -= size;
2849
2850
0
    return size;
2851
0
}
2852
2853
static int
2854
0
xmlMemClose(void *vctxt) {
2855
0
    xmlMemIOCtxt *ctxt = vctxt;
2856
2857
0
    if (ctxt->mem != 0)
2858
0
        xmlFree(ctxt->mem);
2859
0
    xmlFree(ctxt);
2860
0
    return(0);
2861
0
}
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
0
xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2884
0
    xmlParserInputBufferPtr buf;
2885
0
    xmlMemIOCtxt *ctxt;
2886
0
    char *copy;
2887
2888
0
    if ((size < 0) || (mem == NULL))
2889
0
        return(NULL);
2890
2891
0
    copy = (char *) xmlStrndup((const xmlChar *) mem, size);
2892
0
    if (copy == NULL)
2893
0
        return(NULL);
2894
2895
0
    buf = xmlParserInputBufferCreateStatic(copy, size, enc);
2896
0
    if (buf == NULL) {
2897
0
        xmlFree(copy);
2898
0
        return(NULL);
2899
0
    }
2900
2901
0
    ctxt = buf->context;
2902
0
    ctxt->mem = copy;
2903
2904
0
    return(buf);
2905
0
}
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
0
                                 xmlCharEncoding enc) {
2928
0
    xmlParserInputBufferPtr ret;
2929
0
    xmlMemIOCtxt *ctxt;
2930
2931
0
    if ((size < 0) || (mem == NULL))
2932
0
        return(NULL);
2933
2934
0
    ret = xmlAllocParserInputBuffer(enc);
2935
0
    if (ret == NULL)
2936
0
        return(NULL);
2937
2938
0
    ctxt = xmlMalloc(sizeof(*ctxt));
2939
0
    if (ctxt == NULL) {
2940
0
        xmlFreeParserInputBuffer(ret);
2941
0
        return(NULL);
2942
0
    }
2943
0
    ctxt->mem = NULL;
2944
0
    ctxt->cur = mem;
2945
0
    ctxt->size = size;
2946
2947
0
    ret->context = ctxt;
2948
0
    ret->readcallback = xmlMemRead;
2949
0
    ret->closecallback = xmlMemClose;
2950
2951
0
    return(ret);
2952
0
}
2953
2954
typedef struct {
2955
    const xmlChar *str;
2956
} xmlStringIOCtxt;
2957
2958
static int
2959
0
xmlStringRead(void *vctxt, char *buf, int size) {
2960
0
    xmlStringIOCtxt *ctxt = vctxt;
2961
0
    const xmlChar *zero;
2962
0
    size_t len;
2963
2964
0
    zero = memchr(ctxt->str, 0, size);
2965
0
    len = zero ? zero - ctxt->str : size;
2966
2967
0
    memcpy(buf, ctxt->str, len);
2968
0
    ctxt->str += len;
2969
2970
0
    return(len);
2971
0
}
2972
2973
static int
2974
0
xmlStringClose(void *vctxt) {
2975
0
    xmlFree(vctxt);
2976
0
    return(0);
2977
0
}
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
0
xmlParserInputBufferCreateString(const xmlChar *str) {
2990
0
    xmlParserInputBufferPtr ret;
2991
0
    xmlStringIOCtxt *ctxt;
2992
2993
0
    if (str == NULL) return(NULL);
2994
2995
0
    ret = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
2996
0
    if (ret == NULL)
2997
0
        return(NULL);
2998
2999
0
    ctxt = xmlMalloc(sizeof(*ctxt));
3000
0
    if (ctxt == NULL) {
3001
0
        xmlFreeParserInputBuffer(ret);
3002
0
        return(NULL);
3003
0
    }
3004
0
    ctxt->str = str;
3005
3006
0
    ret->context = ctxt;
3007
0
    ret->readcallback = xmlStringRead;
3008
0
    ret->closecallback = xmlStringClose;
3009
3010
0
    return(ret);
3011
0
}
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
0
xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3026
0
    xmlOutputBufferPtr ret;
3027
3028
0
    if (fd < 0) return(NULL);
3029
3030
0
    ret = xmlAllocOutputBufferInternal(encoder);
3031
0
    if (ret != NULL) {
3032
0
        ret->context = (void *) (ptrdiff_t) fd;
3033
0
  ret->writecallback = xmlFdWrite;
3034
0
  ret->closecallback = NULL;
3035
0
    }
3036
3037
0
    return(ret);
3038
0
}
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
0
   xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
3056
0
    xmlParserInputBufferPtr ret;
3057
3058
0
    if (ioread == NULL) return(NULL);
3059
3060
0
    ret = xmlAllocParserInputBuffer(enc);
3061
0
    if (ret != NULL) {
3062
0
        ret->context = (void *) ioctx;
3063
0
  ret->readcallback = ioread;
3064
0
  ret->closecallback = ioclose;
3065
0
    }
3066
3067
0
    return(ret);
3068
0
}
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
0
   xmlCharEncodingHandlerPtr encoder) {
3087
0
    xmlOutputBufferPtr ret;
3088
3089
0
    if (iowrite == NULL) return(NULL);
3090
3091
0
    ret = xmlAllocOutputBufferInternal(encoder);
3092
0
    if (ret != NULL) {
3093
0
        ret->context = (void *) ioctx;
3094
0
  ret->writecallback = iowrite;
3095
0
  ret->closecallback = ioclose;
3096
0
    }
3097
3098
0
    return(ret);
3099
0
}
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
0
{
3113
0
    xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3114
0
    if (old == NULL) {
3115
0
    old = __xmlParserInputBufferCreateFilename;
3116
0
  }
3117
3118
0
    xmlParserInputBufferCreateFilenameValue = func;
3119
0
    return(old);
3120
0
}
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
0
{
3133
0
    xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3134
0
#ifdef LIBXML_OUTPUT_ENABLED
3135
0
    if (old == NULL) {
3136
0
    old = __xmlOutputBufferCreateFilename;
3137
0
  }
3138
0
#endif
3139
0
    xmlOutputBufferCreateFilenameValue = func;
3140
0
    return(old);
3141
0
}
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
84.8k
                   int len, const char *buf) {
3159
84.8k
    int nbchars = 0;
3160
84.8k
    int ret;
3161
3162
84.8k
    if (len < 0) return(0);
3163
84.8k
    if ((in == NULL) || (in->error)) return(-1);
3164
84.8k
    if (in->encoder != NULL) {
3165
        /*
3166
   * Store the data in the incoming raw buffer
3167
   */
3168
44.0k
        if (in->raw == NULL) {
3169
0
      in->raw = xmlBufCreate();
3170
0
            if (in->raw == NULL) {
3171
0
                in->error = XML_ERR_NO_MEMORY;
3172
0
                return(-1);
3173
0
            }
3174
0
  }
3175
44.0k
  ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
3176
44.0k
  if (ret != 0) {
3177
0
            in->error = XML_ERR_NO_MEMORY;
3178
0
      return(-1);
3179
0
        }
3180
3181
  /*
3182
   * convert as much as possible to the parser reading buffer.
3183
   */
3184
44.0k
  nbchars = xmlCharEncInput(in);
3185
44.0k
  if (nbchars < 0)
3186
44
      return(-1);
3187
44.0k
    } else {
3188
40.8k
  nbchars = len;
3189
40.8k
        ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
3190
40.8k
  if (ret != 0) {
3191
0
            in->error = XML_ERR_NO_MEMORY;
3192
0
      return(-1);
3193
0
        }
3194
40.8k
    }
3195
84.8k
    return(nbchars);
3196
84.8k
}
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
0
      int len ATTRIBUTE_UNUSED) {
3208
0
    return(0);
3209
0
}
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
0
xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3228
0
    xmlBufPtr buf;
3229
0
    int res = 0;
3230
3231
0
    if ((in == NULL) || (in->error)) return(-1);
3232
0
    if ((len <= MINLEN) && (len != 4))
3233
0
        len = MINLEN;
3234
3235
0
    if (in->encoder == NULL) {
3236
0
        if (in->readcallback == NULL)
3237
0
            return(0);
3238
0
        buf = in->buffer;
3239
0
    } else {
3240
0
        if (in->raw == NULL) {
3241
0
      in->raw = xmlBufCreate();
3242
0
  }
3243
0
        buf = in->raw;
3244
0
    }
3245
3246
    /*
3247
     * Call the read method for this I/O type.
3248
     */
3249
0
    if (in->readcallback != NULL) {
3250
0
        if (xmlBufGrow(buf, len + 1) < 0) {
3251
0
            in->error = XML_ERR_NO_MEMORY;
3252
0
            return(-1);
3253
0
        }
3254
3255
0
  res = in->readcallback(in->context, (char *)xmlBufEnd(buf), len);
3256
0
  if (res <= 0)
3257
0
      in->readcallback = endOfInput;
3258
0
        if (res < 0) {
3259
0
            in->error = XML_IO_UNKNOWN;
3260
0
            return(-1);
3261
0
        }
3262
3263
0
        if (xmlBufAddLen(buf, res) < 0) {
3264
0
            in->error = XML_ERR_NO_MEMORY;
3265
0
            return(-1);
3266
0
        }
3267
0
    }
3268
3269
    /*
3270
     * try to establish compressed status of input if not done already
3271
     */
3272
0
    if (in->compressed == -1) {
3273
#ifdef LIBXML_LZMA_ENABLED
3274
  if (in->readcallback == xmlXzfileRead)
3275
            in->compressed = __libxml2_xzcompressed(in->context);
3276
#endif
3277
0
    }
3278
3279
0
    if (in->encoder != NULL) {
3280
0
  res = xmlCharEncInput(in);
3281
0
  if (res < 0)
3282
0
      return(-1);
3283
0
    }
3284
0
    return(res);
3285
0
}
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
0
xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
3301
0
    return(xmlParserInputBufferGrow(in, len));
3302
0
}
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
0
xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3321
0
    int nbchars = 0; /* number of chars to output to I/O */
3322
0
    int ret;         /* return from function call */
3323
0
    int written = 0; /* number of char written to I/O so far */
3324
0
    int chunk;       /* number of byte current processed from buf */
3325
3326
0
    if ((out == NULL) || (out->error)) return(-1);
3327
0
    if (len < 0) return(0);
3328
0
    if (out->error) return(-1);
3329
3330
0
    do {
3331
0
  chunk = len;
3332
0
  if (chunk > 4 * MINLEN)
3333
0
      chunk = 4 * MINLEN;
3334
3335
  /*
3336
   * first handle encoding stuff.
3337
   */
3338
0
  if (out->encoder != NULL) {
3339
      /*
3340
       * Store the data in the incoming raw buffer
3341
       */
3342
0
      if (out->conv == NULL) {
3343
0
    out->conv = xmlBufCreate();
3344
0
      }
3345
0
      ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3346
0
      if (ret != 0)
3347
0
          return(-1);
3348
3349
0
      if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
3350
0
    goto done;
3351
3352
      /*
3353
       * convert as much as possible to the parser reading buffer.
3354
       */
3355
0
      ret = xmlCharEncOutput(out, 0);
3356
0
      if ((ret < 0) && (ret != -3)) {
3357
0
    xmlIOErr(XML_IO_ENCODER, NULL);
3358
0
    out->error = XML_IO_ENCODER;
3359
0
    return(-1);
3360
0
      }
3361
0
            if (out->writecallback)
3362
0
          nbchars = xmlBufUse(out->conv);
3363
0
            else
3364
0
                nbchars = ret >= 0 ? ret : 0;
3365
0
  } else {
3366
0
      ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3367
0
      if (ret != 0)
3368
0
          return(-1);
3369
0
            if (out->writecallback)
3370
0
          nbchars = xmlBufUse(out->buffer);
3371
0
            else
3372
0
                nbchars = chunk;
3373
0
  }
3374
0
  buf += chunk;
3375
0
  len -= chunk;
3376
3377
0
  if (out->writecallback) {
3378
0
            if ((nbchars < MINLEN) && (len <= 0))
3379
0
                goto done;
3380
3381
      /*
3382
       * second write the stuff to the I/O channel
3383
       */
3384
0
      if (out->encoder != NULL) {
3385
0
    ret = out->writecallback(out->context,
3386
0
                           (const char *)xmlBufContent(out->conv), nbchars);
3387
0
    if (ret >= 0)
3388
0
        xmlBufShrink(out->conv, ret);
3389
0
      } else {
3390
0
    ret = out->writecallback(out->context,
3391
0
                           (const char *)xmlBufContent(out->buffer), nbchars);
3392
0
    if (ret >= 0)
3393
0
        xmlBufShrink(out->buffer, ret);
3394
0
      }
3395
0
      if (ret < 0) {
3396
0
    xmlIOErr(XML_IO_WRITE, NULL);
3397
0
    out->error = XML_IO_WRITE;
3398
0
    return(ret);
3399
0
      }
3400
0
            if (out->written > INT_MAX - ret)
3401
0
                out->written = INT_MAX;
3402
0
            else
3403
0
                out->written += ret;
3404
0
  }
3405
0
  written += nbchars;
3406
0
    } while (len > 0);
3407
3408
0
done:
3409
0
    return(written);
3410
0
}
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
0
                 const xmlChar* in, int *inlen) {
3428
0
    unsigned char* outstart = out;
3429
0
    const unsigned char* base = in;
3430
0
    unsigned char* outend = out + *outlen;
3431
0
    const unsigned char* inend;
3432
3433
0
    inend = in + (*inlen);
3434
3435
0
    while ((in < inend) && (out < outend)) {
3436
0
  if (*in == '<') {
3437
0
      if (outend - out < 4) break;
3438
0
      *out++ = '&';
3439
0
      *out++ = 'l';
3440
0
      *out++ = 't';
3441
0
      *out++ = ';';
3442
0
  } else if (*in == '>') {
3443
0
      if (outend - out < 4) break;
3444
0
      *out++ = '&';
3445
0
      *out++ = 'g';
3446
0
      *out++ = 't';
3447
0
      *out++ = ';';
3448
0
  } else if (*in == '&') {
3449
0
      if (outend - out < 5) break;
3450
0
      *out++ = '&';
3451
0
      *out++ = 'a';
3452
0
      *out++ = 'm';
3453
0
      *out++ = 'p';
3454
0
      *out++ = ';';
3455
0
  } else if (*in == '\r') {
3456
0
      if (outend - out < 5) break;
3457
0
      *out++ = '&';
3458
0
      *out++ = '#';
3459
0
      *out++ = '1';
3460
0
      *out++ = '3';
3461
0
      *out++ = ';';
3462
0
  } else {
3463
0
      *out++ = *in;
3464
0
  }
3465
0
  ++in;
3466
0
    }
3467
0
    *outlen = out - outstart;
3468
0
    *inlen = in - base;
3469
0
    return(0);
3470
0
}
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
0
                           xmlCharEncodingOutputFunc escaping) {
3490
0
    int nbchars = 0; /* number of chars to output to I/O */
3491
0
    int ret;         /* return from function call */
3492
0
    int written = 0; /* number of char written to I/O so far */
3493
0
    int oldwritten=0;/* loop guard */
3494
0
    int chunk;       /* number of byte currently processed from str */
3495
0
    int len;         /* number of bytes in str */
3496
0
    int cons;        /* byte from str consumed */
3497
3498
0
    if ((out == NULL) || (out->error) || (str == NULL) ||
3499
0
        (out->buffer == NULL))
3500
0
        return(-1);
3501
0
    len = strlen((const char *)str);
3502
0
    if (len < 0) return(0);
3503
0
    if (out->error) return(-1);
3504
0
    if (escaping == NULL) escaping = xmlEscapeContent;
3505
3506
0
    do {
3507
0
        oldwritten = written;
3508
3509
        /*
3510
   * how many bytes to consume and how many bytes to store.
3511
   */
3512
0
  cons = len;
3513
0
  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
0
  if (chunk < 40) {
3520
0
      if (xmlBufGrow(out->buffer, 100) < 0)
3521
0
          return(-1);
3522
0
            oldwritten = -1;
3523
0
      continue;
3524
0
  }
3525
3526
  /*
3527
   * first handle encoding stuff.
3528
   */
3529
0
  if (out->encoder != NULL) {
3530
      /*
3531
       * Store the data in the incoming raw buffer
3532
       */
3533
0
      if (out->conv == NULL) {
3534
0
    out->conv = xmlBufCreate();
3535
0
      }
3536
0
      ret = escaping(xmlBufEnd(out->buffer) ,
3537
0
                     &chunk, str, &cons);
3538
0
      if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3539
0
          return(-1);
3540
0
            xmlBufAddLen(out->buffer, chunk);
3541
3542
0
      if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
3543
0
    goto done;
3544
3545
      /*
3546
       * convert as much as possible to the output buffer.
3547
       */
3548
0
      ret = xmlCharEncOutput(out, 0);
3549
0
      if ((ret < 0) && (ret != -3)) {
3550
0
    xmlIOErr(XML_IO_ENCODER, NULL);
3551
0
    out->error = XML_IO_ENCODER;
3552
0
    return(-1);
3553
0
      }
3554
0
            if (out->writecallback)
3555
0
          nbchars = xmlBufUse(out->conv);
3556
0
            else
3557
0
                nbchars = ret >= 0 ? ret : 0;
3558
0
  } else {
3559
0
      ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
3560
0
      if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3561
0
          return(-1);
3562
0
            xmlBufAddLen(out->buffer, chunk);
3563
0
            if (out->writecallback)
3564
0
          nbchars = xmlBufUse(out->buffer);
3565
0
            else
3566
0
                nbchars = chunk;
3567
0
  }
3568
0
  str += cons;
3569
0
  len -= cons;
3570
3571
0
  if (out->writecallback) {
3572
0
            if ((nbchars < MINLEN) && (len <= 0))
3573
0
                goto done;
3574
3575
      /*
3576
       * second write the stuff to the I/O channel
3577
       */
3578
0
      if (out->encoder != NULL) {
3579
0
    ret = out->writecallback(out->context,
3580
0
                           (const char *)xmlBufContent(out->conv), nbchars);
3581
0
    if (ret >= 0)
3582
0
        xmlBufShrink(out->conv, ret);
3583
0
      } else {
3584
0
    ret = out->writecallback(out->context,
3585
0
                           (const char *)xmlBufContent(out->buffer), nbchars);
3586
0
    if (ret >= 0)
3587
0
        xmlBufShrink(out->buffer, ret);
3588
0
      }
3589
0
      if (ret < 0) {
3590
0
    xmlIOErr(XML_IO_WRITE, NULL);
3591
0
    out->error = XML_IO_WRITE;
3592
0
    return(ret);
3593
0
      }
3594
0
            if (out->written > INT_MAX - ret)
3595
0
                out->written = INT_MAX;
3596
0
            else
3597
0
                out->written += ret;
3598
0
  } else if (xmlBufAvail(out->buffer) < MINLEN) {
3599
0
      xmlBufGrow(out->buffer, MINLEN);
3600
0
  }
3601
0
  written += nbchars;
3602
0
    } while ((len > 0) && (oldwritten != written));
3603
3604
0
done:
3605
0
    return(written);
3606
0
}
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
0
xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3623
0
    int len;
3624
3625
0
    if ((out == NULL) || (out->error)) return(-1);
3626
0
    if (str == NULL)
3627
0
        return(-1);
3628
0
    len = strlen(str);
3629
3630
0
    if (len > 0)
3631
0
  return(xmlOutputBufferWrite(out, len, str));
3632
0
    return(len);
3633
0
}
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
0
xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3645
0
    int nbchars = 0, ret = 0;
3646
3647
0
    if ((out == NULL) || (out->error)) return(-1);
3648
    /*
3649
     * first handle encoding stuff.
3650
     */
3651
0
    if ((out->conv != NULL) && (out->encoder != NULL)) {
3652
  /*
3653
   * convert as much as possible to the parser output buffer.
3654
   */
3655
0
  do {
3656
0
      nbchars = xmlCharEncOutput(out, 0);
3657
0
      if (nbchars < 0) {
3658
0
    xmlIOErr(XML_IO_ENCODER, NULL);
3659
0
    out->error = XML_IO_ENCODER;
3660
0
    return(-1);
3661
0
      }
3662
0
  } while (nbchars);
3663
0
    }
3664
3665
    /*
3666
     * second flush the stuff to the I/O channel
3667
     */
3668
0
    if ((out->conv != NULL) && (out->encoder != NULL) &&
3669
0
  (out->writecallback != NULL)) {
3670
0
  ret = out->writecallback(out->context,
3671
0
                                 (const char *)xmlBufContent(out->conv),
3672
0
                                 xmlBufUse(out->conv));
3673
0
  if (ret >= 0)
3674
0
      xmlBufShrink(out->conv, ret);
3675
0
    } else if (out->writecallback != NULL) {
3676
0
  ret = out->writecallback(out->context,
3677
0
                                 (const char *)xmlBufContent(out->buffer),
3678
0
                                 xmlBufUse(out->buffer));
3679
0
  if (ret >= 0)
3680
0
      xmlBufShrink(out->buffer, ret);
3681
0
    }
3682
0
    if (ret < 0) {
3683
0
  xmlIOErr(XML_IO_FLUSH, NULL);
3684
0
  out->error = XML_IO_FLUSH;
3685
0
  return(ret);
3686
0
    }
3687
0
    if (out->written > INT_MAX - ret)
3688
0
        out->written = INT_MAX;
3689
0
    else
3690
0
        out->written += ret;
3691
3692
0
    return(ret);
3693
0
}
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
0
xmlParserGetDirectory(const char *filename) {
3706
0
    char *ret = NULL;
3707
0
    char dir[1024];
3708
0
    char *cur;
3709
3710
0
    if (xmlInputCallbackInitialized == 0)
3711
0
  xmlRegisterDefaultInputCallbacks();
3712
3713
0
    if (filename == NULL) return(NULL);
3714
3715
#if defined(_WIN32)
3716
#   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3717
#else
3718
0
#   define IS_XMLPGD_SEP(ch) (ch=='/')
3719
0
#endif
3720
3721
0
    strncpy(dir, filename, 1023);
3722
0
    dir[1023] = 0;
3723
0
    cur = &dir[strlen(dir)];
3724
0
    while (cur > dir) {
3725
0
         if (IS_XMLPGD_SEP(*cur)) break;
3726
0
   cur --;
3727
0
    }
3728
0
    if (IS_XMLPGD_SEP(*cur)) {
3729
0
        if (cur == dir) dir[1] = 0;
3730
0
  else *cur = 0;
3731
0
  ret = xmlMemStrdup(dir);
3732
0
    } else {
3733
0
        if (getcwd(dir, 1024) != NULL) {
3734
0
      dir[1023] = 0;
3735
0
      ret = xmlMemStrdup(dir);
3736
0
  }
3737
0
    }
3738
0
    return(ret);
3739
0
#undef IS_XMLPGD_SEP
3740
0
}
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
0
xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3762
    /* Avoid unused variable warning if features are disabled. */
3763
0
    (void) ctxt;
3764
3765
0
#ifdef LIBXML_HTTP_ENABLED
3766
0
    if ((ret != NULL) && (ret->buf != NULL) &&
3767
0
        (ret->buf->readcallback == xmlIOHTTPRead) &&
3768
0
        (ret->buf->context != NULL)) {
3769
0
        const char *encoding;
3770
0
        const char *redir;
3771
0
        const char *mime;
3772
0
        int code;
3773
3774
0
        code = xmlNanoHTTPReturnCode(ret->buf->context);
3775
0
        if (code >= 400) {
3776
            /* fatal error */
3777
0
      if (ret->filename != NULL)
3778
0
    __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
3779
0
                         (const char *) ret->filename);
3780
0
      else
3781
0
    __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
3782
0
            xmlFreeInputStream(ret);
3783
0
            ret = NULL;
3784
0
        } else {
3785
3786
0
            mime = xmlNanoHTTPMimeType(ret->buf->context);
3787
0
            if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3788
0
                (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3789
0
                encoding = xmlNanoHTTPEncoding(ret->buf->context);
3790
0
                if (encoding != NULL) {
3791
0
                    xmlCharEncodingHandlerPtr handler;
3792
3793
0
                    handler = xmlFindCharEncodingHandler(encoding);
3794
0
                    if (handler != NULL) {
3795
0
                        xmlSwitchInputEncoding(ctxt, ret, handler);
3796
0
                    } else {
3797
0
                        __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3798
0
                                         "Unknown encoding %s",
3799
0
                                         BAD_CAST encoding, NULL);
3800
0
                    }
3801
0
                }
3802
#if 0
3803
            } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3804
#endif
3805
0
            }
3806
0
            redir = xmlNanoHTTPRedir(ret->buf->context);
3807
0
            if (redir != NULL) {
3808
0
                if (ret->filename != NULL)
3809
0
                    xmlFree((xmlChar *) ret->filename);
3810
0
                if (ret->directory != NULL) {
3811
0
                    xmlFree((xmlChar *) ret->directory);
3812
0
                    ret->directory = NULL;
3813
0
                }
3814
0
                ret->filename =
3815
0
                    (char *) xmlStrdup((const xmlChar *) redir);
3816
0
            }
3817
0
        }
3818
0
    }
3819
0
#endif
3820
0
    return(ret);
3821
0
}
3822
3823
0
static int xmlNoNetExists(const char *URL) {
3824
0
    const char *path;
3825
3826
0
    if (URL == NULL)
3827
0
  return(0);
3828
3829
0
    if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
3830
#if defined (_WIN32)
3831
  path = &URL[17];
3832
#else
3833
0
  path = &URL[16];
3834
0
#endif
3835
0
    else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
3836
#if defined (_WIN32)
3837
  path = &URL[8];
3838
#else
3839
0
  path = &URL[7];
3840
0
#endif
3841
0
    } else
3842
0
  path = URL;
3843
3844
0
    return xmlCheckFilename(path);
3845
0
}
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
0
                              xmlParserCtxtPtr ctxt) {
3864
0
    xmlChar *resource = NULL;
3865
0
    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
0
    pref = xmlCatalogGetDefaults();
3872
3873
0
    if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3874
  /*
3875
   * Do a local lookup
3876
   */
3877
0
  if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3878
0
      ((pref == XML_CATA_ALLOW_ALL) ||
3879
0
       (pref == XML_CATA_ALLOW_DOCUMENT))) {
3880
0
      resource = xmlCatalogLocalResolve(ctxt->catalogs,
3881
0
                (const xmlChar *)ID,
3882
0
                (const xmlChar *)URL);
3883
0
        }
3884
  /*
3885
   * Try a global lookup
3886
   */
3887
0
  if ((resource == NULL) &&
3888
0
      ((pref == XML_CATA_ALLOW_ALL) ||
3889
0
       (pref == XML_CATA_ALLOW_GLOBAL))) {
3890
0
      resource = xmlCatalogResolve((const xmlChar *)ID,
3891
0
           (const xmlChar *)URL);
3892
0
  }
3893
0
  if ((resource == NULL) && (URL != NULL))
3894
0
      resource = xmlStrdup((const xmlChar *) URL);
3895
3896
  /*
3897
   * TODO: do an URI lookup on the reference
3898
   */
3899
0
  if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3900
0
      xmlChar *tmp = NULL;
3901
3902
0
      if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3903
0
    ((pref == XML_CATA_ALLOW_ALL) ||
3904
0
     (pref == XML_CATA_ALLOW_DOCUMENT))) {
3905
0
    tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3906
0
      }
3907
0
      if ((tmp == NULL) &&
3908
0
    ((pref == XML_CATA_ALLOW_ALL) ||
3909
0
           (pref == XML_CATA_ALLOW_GLOBAL))) {
3910
0
    tmp = xmlCatalogResolveURI(resource);
3911
0
      }
3912
3913
0
      if (tmp != NULL) {
3914
0
    xmlFree(resource);
3915
0
    resource = tmp;
3916
0
      }
3917
0
  }
3918
0
    }
3919
3920
0
    return resource;
3921
0
}
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
0
{
3939
0
    xmlParserInputPtr ret = NULL;
3940
0
    xmlChar *resource = NULL;
3941
3942
0
    if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
3943
0
        int options = ctxt->options;
3944
3945
0
  ctxt->options -= XML_PARSE_NONET;
3946
0
        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
3947
0
  ctxt->options = options;
3948
0
  return(ret);
3949
0
    }
3950
0
#ifdef LIBXML_CATALOG_ENABLED
3951
0
    resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
3952
0
#endif
3953
3954
0
    if (resource == NULL)
3955
0
        resource = (xmlChar *) URL;
3956
3957
0
    if (resource == NULL) {
3958
0
        if (ID == NULL)
3959
0
            ID = "NULL";
3960
0
        __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
3961
0
        return (NULL);
3962
0
    }
3963
0
    ret = xmlNewInputFromFile(ctxt, (const char *) resource);
3964
0
    if ((resource != NULL) && (resource != (xmlChar *) URL))
3965
0
        xmlFree(resource);
3966
0
    return (ret);
3967
0
}
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
0
xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
3980
0
    xmlCurrentExternalEntityLoader = f;
3981
0
}
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
0
xmlGetExternalEntityLoader(void) {
3992
0
    return(xmlCurrentExternalEntityLoader);
3993
0
}
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
0
                      xmlParserCtxtPtr ctxt) {
4009
0
    if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
4010
0
  char *canonicFilename;
4011
0
  xmlParserInputPtr ret;
4012
4013
0
  canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4014
0
  if (canonicFilename == NULL) {
4015
0
            xmlErrMemory(ctxt, "building canonical path\n");
4016
0
      return(NULL);
4017
0
  }
4018
4019
0
  ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4020
0
  xmlFree(canonicFilename);
4021
0
  return(ret);
4022
0
    }
4023
0
    return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4024
0
}
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
0
                             xmlParserCtxtPtr ctxt) {
4046
0
    xmlParserInputPtr input = NULL;
4047
0
    xmlChar *resource = NULL;
4048
4049
0
#ifdef LIBXML_CATALOG_ENABLED
4050
0
    resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4051
0
#endif
4052
4053
0
    if (resource == NULL)
4054
0
  resource = (xmlChar *) URL;
4055
4056
0
    if (resource != NULL) {
4057
0
        if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4058
0
            (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
4059
0
            xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
4060
0
      if (resource != (xmlChar *) URL)
4061
0
    xmlFree(resource);
4062
0
      return(NULL);
4063
0
  }
4064
0
    }
4065
0
    input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4066
0
    if (resource != (xmlChar *) URL)
4067
0
  xmlFree(resource);
4068
0
    return(input);
4069
0
}
4070