Coverage Report

Created: 2024-01-18 20:16

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