Coverage Report

Created: 2022-11-15 06:34

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