Coverage Report

Created: 2025-08-04 07:15

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