Coverage Report

Created: 2023-06-07 06:06

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