Coverage Report

Created: 2023-12-13 20:02

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