Coverage Report

Created: 2023-06-07 06:14

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