Coverage Report

Created: 2025-07-23 08:18

/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
 * Author: Daniel Veillard
7
 */
8
9
#define IN_LIBXML
10
#include "libxml.h"
11
12
#include <string.h>
13
#include <stdlib.h>
14
#include <errno.h>
15
16
#include <fcntl.h>
17
#include <sys/stat.h>
18
19
#if defined(_WIN32)
20
  #define WIN32_LEAN_AND_MEAN
21
  #include <windows.h>
22
  #include <io.h>
23
  #include <direct.h>
24
#else
25
  #include <unistd.h>
26
#endif
27
28
#ifdef LIBXML_ZLIB_ENABLED
29
#include <zlib.h>
30
#endif
31
#ifdef LIBXML_LZMA_ENABLED
32
#include <lzma.h>
33
#endif
34
35
#include <libxml/xmlIO.h>
36
#include <libxml/xmlmemory.h>
37
#include <libxml/uri.h>
38
#include <libxml/parserInternals.h>
39
#include <libxml/xmlerror.h>
40
#ifdef LIBXML_CATALOG_ENABLED
41
#include <libxml/catalog.h>
42
#endif
43
44
#include "private/buf.h"
45
#include "private/enc.h"
46
#include "private/error.h"
47
#include "private/io.h"
48
49
#ifndef SIZE_MAX
50
  #define SIZE_MAX ((size_t) -1)
51
#endif
52
53
/* #define VERBOSE_FAILURE */
54
55
0
#define MINLEN 4000
56
57
#ifndef STDOUT_FILENO
58
  #define STDOUT_FILENO 1
59
#endif
60
61
#ifndef S_ISDIR
62
#  ifdef _S_ISDIR
63
#    define S_ISDIR(x) _S_ISDIR(x)
64
#  elif defined(S_IFDIR)
65
#    ifdef S_IFMT
66
#      define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
67
#    elif defined(_S_IFMT)
68
#      define S_ISDIR(m) (((m) & _S_IFMT) == S_IFDIR)
69
#    endif
70
#  endif
71
#endif
72
73
/*
74
 * Input I/O callback sets
75
 */
76
typedef struct _xmlInputCallback {
77
    xmlInputMatchCallback matchcallback;
78
    xmlInputOpenCallback opencallback;
79
    xmlInputReadCallback readcallback;
80
    xmlInputCloseCallback closecallback;
81
} xmlInputCallback;
82
83
/* This dummy function only marks default IO in the callback table */
84
static int
85
xmlIODefaultMatch(const char *filename);
86
87
0
#define MAX_INPUT_CALLBACK 10
88
89
static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
90
static int xmlInputCallbackNr;
91
92
#ifdef LIBXML_OUTPUT_ENABLED
93
/*
94
 * Output I/O callback sets
95
 */
96
typedef struct _xmlOutputCallback {
97
    xmlOutputMatchCallback matchcallback;
98
    xmlOutputOpenCallback opencallback;
99
    xmlOutputWriteCallback writecallback;
100
    xmlOutputCloseCallback closecallback;
101
} xmlOutputCallback;
102
103
0
#define MAX_OUTPUT_CALLBACK 10
104
105
static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
106
static int xmlOutputCallbackNr;
107
#endif /* LIBXML_OUTPUT_ENABLED */
108
109
/************************************************************************
110
 *                  *
111
 *      Special escaping routines     *
112
 *                  *
113
 ************************************************************************/
114
115
/*
116
 * @param buf  a char buffer
117
 * @param val  a codepoint
118
 *
119
 * Serializes a hex char ref like `&#xA0;`.
120
 *
121
 * Writes at most 9 bytes. Does not include a terminating zero byte.
122
 *
123
 * @returns the number of bytes written.
124
 */
125
static int
126
0
xmlSerializeHexCharRef(char *buf, int val) {
127
0
    char *out = buf;
128
0
    int shift = 0, bits;
129
130
0
    *out++ = '&';
131
0
    *out++ = '#';
132
0
    *out++ = 'x';
133
134
0
    bits = val;
135
0
    if (bits & 0xFF0000) {
136
0
        shift = 16;
137
0
        bits &= 0xFF0000;
138
0
    } else if (bits & 0x00FF00) {
139
0
        shift = 8;
140
0
        bits &= 0x00FF00;
141
0
    }
142
0
    if (bits & 0xF0F0F0) {
143
0
        shift += 4;
144
0
    }
145
146
0
    do {
147
0
        int d = (val >> shift) & 0x0F;
148
149
0
        if (d < 10)
150
0
            *out++ = '0' + d;
151
0
        else
152
0
            *out++ = 'A' + (d - 10);
153
154
0
  shift -= 4;
155
0
    } while (shift >= 0);
156
157
0
    *out++ = ';';
158
159
0
    return(out - buf);
160
0
}
161
162
#include "codegen/escape.inc"
163
164
/*
165
 * @param text  input text
166
 * @param flags  XML_ESCAPE flags
167
 *
168
 * Escapes certain characters with char refs.
169
 *
170
 * - XML_ESCAPE_ATTR: for attribute content.
171
 * - XML_ESCAPE_NON_ASCII: escape non-ASCII chars.
172
 * - XML_ESCAPE_HTML: for HTML content.
173
 * - XML_ESCAPE_QUOT: escape double quotes.
174
 *
175
 * @returns an escaped string or NULL if a memory allocation failed.
176
 */
177
xmlChar *
178
0
xmlEscapeText(const xmlChar *string, int flags) {
179
0
    const xmlChar *cur;
180
0
    xmlChar *buffer;
181
0
    xmlChar *out;
182
0
    const signed char *tab;
183
0
    size_t size = 50;
184
185
0
#ifdef LIBXML_HTML_ENABLED
186
0
    if (flags & XML_ESCAPE_HTML) {
187
0
        if (flags & XML_ESCAPE_ATTR)
188
0
            tab = htmlEscapeTabAttr;
189
0
        else
190
0
            tab = htmlEscapeTab;
191
0
    }
192
0
    else
193
0
#endif
194
0
    {
195
0
        if (flags & XML_ESCAPE_QUOT)
196
0
            tab = xmlEscapeTabQuot;
197
0
        else if (flags & XML_ESCAPE_ATTR)
198
0
            tab = xmlEscapeTabAttr;
199
0
        else
200
0
            tab = xmlEscapeTab;
201
0
    }
202
203
0
    buffer = xmlMalloc(size + 1);
204
0
    if (buffer == NULL)
205
0
        return(NULL);
206
0
    out = buffer;
207
208
0
    cur = string;
209
210
0
    while (*cur != 0) {
211
0
        char tempBuf[12];
212
0
        const xmlChar *base;
213
0
        const char *repl;
214
0
        size_t used;
215
0
        size_t replSize;
216
0
        size_t unescapedSize;
217
0
        size_t totalSize;
218
0
        int c;
219
0
        int offset;
220
221
0
        base = cur;
222
0
        offset = -1;
223
224
0
        while (1) {
225
0
            c = *cur;
226
227
0
            if (c < 0x80) {
228
0
                offset = tab[c];
229
0
                if (offset >= 0)
230
0
                    break;
231
0
            } else if (flags & XML_ESCAPE_NON_ASCII) {
232
0
                break;
233
0
            }
234
235
0
            cur += 1;
236
0
        }
237
238
0
        unescapedSize = cur - base;
239
240
0
        if (offset >= 0) {
241
0
            if (c == 0) {
242
0
                replSize = 0;
243
0
                repl = "";
244
0
            } else {
245
0
                replSize = xmlEscapeContent[offset],
246
0
                repl = &xmlEscapeContent[offset+1];
247
0
                cur += 1;
248
0
            }
249
0
        } else {
250
0
            int val = 0, len = 4;
251
252
0
            val = xmlGetUTF8Char(cur, &len);
253
0
            if (val < 0) {
254
0
                val = 0xFFFD;
255
0
                cur += 1;
256
0
            } else {
257
0
                if ((val == 0xFFFE) || (val == 0xFFFF))
258
0
                    val = 0xFFFD;
259
0
                cur += len;
260
0
            }
261
262
0
            replSize = xmlSerializeHexCharRef(tempBuf, val);
263
0
            repl = tempBuf;
264
0
        }
265
266
0
        used = out - buffer;
267
0
        totalSize = unescapedSize + replSize;
268
269
0
        if (totalSize > size - used) {
270
0
            xmlChar *tmp;
271
0
            int newSize;
272
273
0
            if ((size > (SIZE_MAX - 1) / 2) ||
274
0
                (totalSize > (SIZE_MAX - 1) / 2 - size)) {
275
0
                xmlFree(buffer);
276
0
                return(NULL);
277
0
            }
278
0
            newSize = size + totalSize;
279
0
            if (*cur != 0)
280
0
                newSize *= 2;
281
0
            tmp = xmlRealloc(buffer, newSize + 1);
282
0
            if (tmp == NULL) {
283
0
                xmlFree(buffer);
284
0
                return(NULL);
285
0
            }
286
0
            buffer = tmp;
287
0
            size = newSize;
288
0
            out = buffer + used;
289
0
        }
290
291
0
        memcpy(out, base, unescapedSize);
292
0
        out += unescapedSize;
293
0
        memcpy(out, repl, replSize);
294
0
        out += replSize;
295
296
0
        if (c == 0)
297
0
            break;
298
299
0
        base = cur;
300
0
    }
301
302
0
    *out = 0;
303
0
    return(buffer);
304
0
}
305
306
#ifdef LIBXML_OUTPUT_ENABLED
307
void
308
xmlSerializeText(xmlOutputBuffer *buf, const xmlChar *string, size_t maxSize,
309
0
                 unsigned flags) {
310
0
    const xmlChar *cur;
311
0
    const signed char *tab;
312
313
0
    if (string == NULL)
314
0
        return;
315
316
0
#ifdef LIBXML_HTML_ENABLED
317
0
    if (flags & XML_ESCAPE_HTML) {
318
0
        if (flags & XML_ESCAPE_ATTR)
319
0
            tab = htmlEscapeTabAttr;
320
0
        else
321
0
            tab = htmlEscapeTab;
322
0
    }
323
0
    else
324
0
#endif
325
0
    {
326
0
        if (flags & XML_ESCAPE_QUOT)
327
0
            tab = xmlEscapeTabQuot;
328
0
        else if (flags & XML_ESCAPE_ATTR)
329
0
            tab = xmlEscapeTabAttr;
330
0
        else
331
0
            tab = xmlEscapeTab;
332
0
    }
333
334
0
    cur = string;
335
336
0
    while (1) {
337
0
        const xmlChar *base;
338
0
        int c;
339
0
        int offset;
340
341
0
        base = cur;
342
0
        offset = -1;
343
344
0
        while (1) {
345
0
            if ((size_t) (cur - string) >= maxSize)
346
0
                break;
347
348
0
            c = (unsigned char) *cur;
349
350
0
            if (c < 0x80) {
351
0
                offset = tab[c];
352
0
                if (offset >= 0)
353
0
                    break;
354
0
            } else if (flags & XML_ESCAPE_NON_ASCII) {
355
0
                break;
356
0
            }
357
358
0
            cur += 1;
359
0
        }
360
361
0
        if (cur > base)
362
0
            xmlOutputBufferWrite(buf, cur - base, (char *) base);
363
364
0
        if ((size_t) (cur - string) >= maxSize)
365
0
            break;
366
367
0
        if (offset >= 0) {
368
0
            if (c == 0)
369
0
                break;
370
371
0
            xmlOutputBufferWrite(buf, xmlEscapeContent[offset],
372
0
                                 &xmlEscapeContent[offset+1]);
373
0
            cur += 1;
374
0
        } else {
375
0
            char tempBuf[12];
376
0
            int tempSize;
377
0
            int val = 0, len = 4;
378
379
0
            val = xmlGetUTF8Char(cur, &len);
380
0
            if (val < 0) {
381
0
                val = 0xFFFD;
382
0
                cur += 1;
383
0
            } else {
384
0
                if ((val == 0xFFFE) || (val == 0xFFFF))
385
0
                    val = 0xFFFD;
386
0
                cur += len;
387
0
            }
388
389
0
            tempSize = xmlSerializeHexCharRef(tempBuf, val);
390
0
            xmlOutputBufferWrite(buf, tempSize, tempBuf);
391
0
        }
392
0
    }
393
0
}
394
#endif /* LIBXML_OUTPUT_ENABLED */
395
396
/************************************************************************
397
 *                  *
398
 *      Error handling          *
399
 *                  *
400
 ************************************************************************/
401
402
/**
403
 * Convert errno to xmlParserErrors.
404
 *
405
 * @param err  the error number
406
 * @returns an xmlParserErrors code.
407
 */
408
static int
409
xmlIOErr(int err)
410
0
{
411
0
    xmlParserErrors code;
412
413
0
    switch (err) {
414
0
#ifdef EACCES
415
0
        case EACCES: code = XML_IO_EACCES; break;
416
0
#endif
417
0
#ifdef EAGAIN
418
0
        case EAGAIN: code = XML_IO_EAGAIN; break;
419
0
#endif
420
0
#ifdef EBADF
421
0
        case EBADF: code = XML_IO_EBADF; break;
422
0
#endif
423
0
#ifdef EBADMSG
424
0
        case EBADMSG: code = XML_IO_EBADMSG; break;
425
0
#endif
426
0
#ifdef EBUSY
427
0
        case EBUSY: code = XML_IO_EBUSY; break;
428
0
#endif
429
0
#ifdef ECANCELED
430
0
        case ECANCELED: code = XML_IO_ECANCELED; break;
431
0
#endif
432
0
#ifdef ECHILD
433
0
        case ECHILD: code = XML_IO_ECHILD; break;
434
0
#endif
435
0
#ifdef EDEADLK
436
0
        case EDEADLK: code = XML_IO_EDEADLK; break;
437
0
#endif
438
0
#ifdef EDOM
439
0
        case EDOM: code = XML_IO_EDOM; break;
440
0
#endif
441
0
#ifdef EEXIST
442
0
        case EEXIST: code = XML_IO_EEXIST; break;
443
0
#endif
444
0
#ifdef EFAULT
445
0
        case EFAULT: code = XML_IO_EFAULT; break;
446
0
#endif
447
0
#ifdef EFBIG
448
0
        case EFBIG: code = XML_IO_EFBIG; break;
449
0
#endif
450
0
#ifdef EINPROGRESS
451
0
        case EINPROGRESS: code = XML_IO_EINPROGRESS; break;
452
0
#endif
453
0
#ifdef EINTR
454
0
        case EINTR: code = XML_IO_EINTR; break;
455
0
#endif
456
0
#ifdef EINVAL
457
0
        case EINVAL: code = XML_IO_EINVAL; break;
458
0
#endif
459
0
#ifdef EIO
460
0
        case EIO: code = XML_IO_EIO; break;
461
0
#endif
462
0
#ifdef EISDIR
463
0
        case EISDIR: code = XML_IO_EISDIR; break;
464
0
#endif
465
0
#ifdef EMFILE
466
0
        case EMFILE: code = XML_IO_EMFILE; break;
467
0
#endif
468
0
#ifdef EMLINK
469
0
        case EMLINK: code = XML_IO_EMLINK; break;
470
0
#endif
471
0
#ifdef EMSGSIZE
472
0
        case EMSGSIZE: code = XML_IO_EMSGSIZE; break;
473
0
#endif
474
0
#ifdef ENAMETOOLONG
475
0
        case ENAMETOOLONG: code = XML_IO_ENAMETOOLONG; break;
476
0
#endif
477
0
#ifdef ENFILE
478
0
        case ENFILE: code = XML_IO_ENFILE; break;
479
0
#endif
480
0
#ifdef ENODEV
481
0
        case ENODEV: code = XML_IO_ENODEV; break;
482
0
#endif
483
0
#ifdef ENOENT
484
0
        case ENOENT: code = XML_IO_ENOENT; break;
485
0
#endif
486
0
#ifdef ENOEXEC
487
0
        case ENOEXEC: code = XML_IO_ENOEXEC; break;
488
0
#endif
489
0
#ifdef ENOLCK
490
0
        case ENOLCK: code = XML_IO_ENOLCK; break;
491
0
#endif
492
0
#ifdef ENOMEM
493
0
        case ENOMEM: code = XML_IO_ENOMEM; break;
494
0
#endif
495
0
#ifdef ENOSPC
496
0
        case ENOSPC: code = XML_IO_ENOSPC; break;
497
0
#endif
498
0
#ifdef ENOSYS
499
0
        case ENOSYS: code = XML_IO_ENOSYS; break;
500
0
#endif
501
0
#ifdef ENOTDIR
502
0
        case ENOTDIR: code = XML_IO_ENOTDIR; break;
503
0
#endif
504
0
#ifdef ENOTEMPTY
505
0
        case ENOTEMPTY: code = XML_IO_ENOTEMPTY; break;
506
0
#endif
507
0
#ifdef ENOTSUP
508
0
        case ENOTSUP: code = XML_IO_ENOTSUP; break;
509
0
#endif
510
0
#ifdef ENOTTY
511
0
        case ENOTTY: code = XML_IO_ENOTTY; break;
512
0
#endif
513
0
#ifdef ENXIO
514
0
        case ENXIO: code = XML_IO_ENXIO; break;
515
0
#endif
516
0
#ifdef EPERM
517
0
        case EPERM: code = XML_IO_EPERM; break;
518
0
#endif
519
0
#ifdef EPIPE
520
0
        case EPIPE: code = XML_IO_EPIPE; break;
521
0
#endif
522
0
#ifdef ERANGE
523
0
        case ERANGE: code = XML_IO_ERANGE; break;
524
0
#endif
525
0
#ifdef EROFS
526
0
        case EROFS: code = XML_IO_EROFS; break;
527
0
#endif
528
0
#ifdef ESPIPE
529
0
        case ESPIPE: code = XML_IO_ESPIPE; break;
530
0
#endif
531
0
#ifdef ESRCH
532
0
        case ESRCH: code = XML_IO_ESRCH; break;
533
0
#endif
534
0
#ifdef ETIMEDOUT
535
0
        case ETIMEDOUT: code = XML_IO_ETIMEDOUT; break;
536
0
#endif
537
0
#ifdef EXDEV
538
0
        case EXDEV: code = XML_IO_EXDEV; break;
539
0
#endif
540
0
#ifdef ENOTSOCK
541
0
        case ENOTSOCK: code = XML_IO_ENOTSOCK; break;
542
0
#endif
543
0
#ifdef EISCONN
544
0
        case EISCONN: code = XML_IO_EISCONN; break;
545
0
#endif
546
0
#ifdef ECONNREFUSED
547
0
        case ECONNREFUSED: code = XML_IO_ECONNREFUSED; break;
548
0
#endif
549
0
#ifdef ENETUNREACH
550
0
        case ENETUNREACH: code = XML_IO_ENETUNREACH; break;
551
0
#endif
552
0
#ifdef EADDRINUSE
553
0
        case EADDRINUSE: code = XML_IO_EADDRINUSE; break;
554
0
#endif
555
0
#ifdef EALREADY
556
0
        case EALREADY: code = XML_IO_EALREADY; break;
557
0
#endif
558
0
#ifdef EAFNOSUPPORT
559
0
        case EAFNOSUPPORT: code = XML_IO_EAFNOSUPPORT; break;
560
0
#endif
561
0
        default: code = XML_IO_UNKNOWN; break;
562
0
    }
563
564
0
    return(code);
565
0
}
566
567
/************************************************************************
568
 *                  *
569
 *    Standard I/O for file accesses        *
570
 *                  *
571
 ************************************************************************/
572
573
#if defined(_WIN32)
574
575
/**
576
 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
577
 *
578
 * @param u8String  uft-8 string
579
 */
580
static wchar_t *
581
__xmlIOWin32UTF8ToWChar(const char *u8String)
582
{
583
    wchar_t *wString = NULL;
584
    int i;
585
586
    if (u8String) {
587
        int wLen =
588
            MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
589
                                -1, NULL, 0);
590
        if (wLen) {
591
            wString = xmlMalloc(wLen * sizeof(wchar_t));
592
            if (wString) {
593
                if (MultiByteToWideChar
594
                    (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
595
                    xmlFree(wString);
596
                    wString = NULL;
597
                }
598
            }
599
600
            /*
601
             * Convert to backward slash
602
             */
603
            for (i = 0; wString[i] != 0; i++) {
604
                if (wString[i] == '/')
605
                    wString[i] = '\\';
606
            }
607
        }
608
    }
609
610
    return wString;
611
}
612
613
#endif
614
615
/**
616
 * @deprecated This never really worked.
617
 *
618
 * @param path  the input file path
619
 * @returns a copy of path.
620
 */
621
xmlChar *
622
xmlNormalizeWindowsPath(const xmlChar *path)
623
0
{
624
0
    return xmlStrdup(path);
625
0
}
626
627
/**
628
 * if stat is not available on the target machine,
629
 *
630
 * @deprecated Internal function, don't use.
631
 *
632
 * @param path  the path to check
633
 * @returns 0 if stat fails, 2 if stat succeeds and the file is
634
 * a directory, 1 otherwise.
635
 */
636
int
637
xmlCheckFilename(const char *path)
638
0
{
639
#if defined(_WIN32)
640
    struct _stat stat_buffer;
641
#else
642
0
    struct stat stat_buffer;
643
0
#endif
644
0
    int res;
645
646
0
    if (path == NULL)
647
0
  return(0);
648
649
#if defined(_WIN32)
650
    {
651
        wchar_t *wpath;
652
653
        /*
654
         * On Windows stat and wstat do not work with long pathname,
655
         * which start with '\\?\'
656
         */
657
        if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
658
            (path[3] == '\\') )
659
                return 1;
660
661
        wpath = __xmlIOWin32UTF8ToWChar(path);
662
        if (wpath == NULL)
663
            return(0);
664
        res = _wstat(wpath, &stat_buffer);
665
        xmlFree(wpath);
666
    }
667
#else
668
0
    res = stat(path, &stat_buffer);
669
0
#endif
670
671
0
    if (res < 0)
672
0
        return 0;
673
674
0
#ifdef S_ISDIR
675
0
    if (S_ISDIR(stat_buffer.st_mode))
676
0
        return 2;
677
0
#endif
678
679
0
    return 1;
680
0
}
681
682
static int
683
0
xmlConvertUriToPath(const char *uri, char **out) {
684
0
    const char *escaped;
685
0
    char *unescaped;
686
687
0
    *out = NULL;
688
689
0
    if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file://localhost/", 17)) {
690
0
  escaped = &uri[16];
691
0
    } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:///", 8)) {
692
0
  escaped = &uri[7];
693
0
    } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:/", 6)) {
694
        /* lots of generators seems to lazy to read RFC 1738 */
695
0
  escaped = &uri[5];
696
0
    } else {
697
0
        return(1);
698
0
    }
699
700
#ifdef _WIN32
701
    /* Ignore slash like in file:///C:/file.txt */
702
    escaped += 1;
703
#endif
704
705
0
    unescaped = xmlURIUnescapeString(escaped, 0, NULL);
706
0
    if (unescaped == NULL)
707
0
        return(-1);
708
709
0
    *out = unescaped;
710
0
    return(0);
711
0
}
712
713
typedef struct {
714
    int fd;
715
} xmlFdIOCtxt;
716
717
/**
718
 * @param filename  the URI for matching
719
 * @param write  whether the fd is opened for writing
720
 * @param out  pointer to resulting context
721
 * @returns an xmlParserErrors code
722
 */
723
static xmlParserErrors
724
0
xmlFdOpen(const char *filename, int write, int *out) {
725
0
    char *fromUri = NULL;
726
0
    int flags;
727
0
    int fd;
728
0
    xmlParserErrors ret;
729
730
0
    *out = -1;
731
0
    if (filename == NULL)
732
0
        return(XML_ERR_ARGUMENT);
733
734
0
    if (xmlConvertUriToPath(filename, &fromUri) < 0)
735
0
        return(XML_ERR_NO_MEMORY);
736
737
0
    if (fromUri != NULL)
738
0
        filename = fromUri;
739
740
#if defined(_WIN32)
741
    {
742
        wchar_t *wpath;
743
744
        wpath = __xmlIOWin32UTF8ToWChar(filename);
745
        if (wpath == NULL) {
746
            xmlFree(fromUri);
747
            return(XML_ERR_NO_MEMORY);
748
        }
749
        if (write)
750
            flags = _O_WRONLY | _O_CREAT | _O_TRUNC;
751
        else
752
            flags = _O_RDONLY;
753
  fd = _wopen(wpath, flags | _O_BINARY, 0666);
754
        xmlFree(wpath);
755
    }
756
#else
757
0
    if (write)
758
0
        flags = O_WRONLY | O_CREAT | O_TRUNC;
759
0
    else
760
0
        flags = O_RDONLY;
761
0
    fd = open(filename, flags, 0666);
762
0
#endif /* WIN32 */
763
764
0
    if (fd < 0) {
765
        /*
766
         * Windows and possibly other platforms return EINVAL
767
         * for invalid filenames.
768
         */
769
0
        if ((errno == ENOENT) || (errno == EINVAL)) {
770
0
            ret = XML_IO_ENOENT;
771
0
        } else {
772
0
            ret = xmlIOErr(errno);
773
0
        }
774
0
    } else {
775
0
        *out = fd;
776
0
        ret = XML_ERR_OK;
777
0
    }
778
779
0
    xmlFree(fromUri);
780
0
    return(ret);
781
0
}
782
783
/**
784
 * Read `len` bytes to `buffer` from the I/O channel.
785
 *
786
 * @param context  the I/O context
787
 * @param buffer  where to drop data
788
 * @param len  number of bytes to read
789
 * @returns the number of bytes read
790
 */
791
static int
792
0
xmlFdRead(void *context, char *buffer, int len) {
793
0
    xmlFdIOCtxt *fdctxt = context;
794
0
    int fd = fdctxt->fd;
795
0
    int ret = 0;
796
0
    int bytes;
797
798
0
    while (len > 0) {
799
0
        bytes = read(fd, buffer, len);
800
0
        if (bytes < 0) {
801
            /*
802
             * If we already got some bytes, return them without
803
             * raising an error.
804
             */
805
0
            if (ret > 0)
806
0
                break;
807
0
            return(-xmlIOErr(errno));
808
0
        }
809
0
        if (bytes == 0)
810
0
            break;
811
0
        ret += bytes;
812
0
        buffer += bytes;
813
0
        len -= bytes;
814
0
    }
815
816
0
    return(ret);
817
0
}
818
819
#ifdef LIBXML_OUTPUT_ENABLED
820
/**
821
 * Write `len` bytes from `buffer` to the I/O channel.
822
 *
823
 * @param context  the I/O context
824
 * @param buffer  where to get data
825
 * @param len  number of bytes to write
826
 * @returns the number of bytes written
827
 */
828
static int
829
0
xmlFdWrite(void *context, const char *buffer, int len) {
830
0
    xmlFdIOCtxt *fdctxt = context;
831
0
    int fd = fdctxt->fd;
832
0
    int ret = 0;
833
0
    int bytes;
834
835
0
    while (len > 0) {
836
0
  bytes = write(fd, buffer, len);
837
0
  if (bytes < 0)
838
0
            return(-xmlIOErr(errno));
839
0
        ret += bytes;
840
0
        buffer += bytes;
841
0
        len -= bytes;
842
0
    }
843
844
0
    return(ret);
845
0
}
846
#endif /* LIBXML_OUTPUT_ENABLED */
847
848
static int
849
0
xmlFdFree(void *context) {
850
0
    xmlFree(context);
851
0
    return(XML_ERR_OK);
852
0
}
853
854
/**
855
 * Close an I/O channel
856
 *
857
 * @param context  the I/O context
858
 * @returns 0 in case of success and error code otherwise
859
 */
860
static int
861
0
xmlFdClose (void * context) {
862
0
    xmlFdIOCtxt *fdctxt = context;
863
0
    int fd = fdctxt->fd;
864
0
    int ret;
865
866
0
    ret = close(fd);
867
868
0
    xmlFree(fdctxt);
869
870
0
    if (ret < 0)
871
0
        return(xmlIOErr(errno));
872
873
0
    return(XML_ERR_OK);
874
0
}
875
876
/**
877
 * @deprecated Internal function, don't use.
878
 *
879
 * @param filename  the URI for matching
880
 * @returns 1 if matches, 0 otherwise
881
 */
882
int
883
0
xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
884
0
    return(1);
885
0
}
886
887
/**
888
 * input from FILE *
889
 *
890
 * @param filename  the URI for matching
891
 * @param write  whether the file is opened for writing
892
 * @param out  pointer to resulting context
893
 * @returns an xmlParserErrors code
894
 */
895
static xmlParserErrors
896
0
xmlFileOpenSafe(const char *filename, int write, void **out) {
897
0
    char *fromUri = NULL;
898
0
    FILE *fd;
899
0
    xmlParserErrors ret = XML_ERR_OK;
900
901
0
    *out = NULL;
902
0
    if (filename == NULL)
903
0
        return(XML_ERR_ARGUMENT);
904
905
0
    if (xmlConvertUriToPath(filename, &fromUri) < 0)
906
0
        return(XML_ERR_NO_MEMORY);
907
908
0
    if (fromUri != NULL)
909
0
        filename = fromUri;
910
911
#if defined(_WIN32)
912
    {
913
        wchar_t *wpath;
914
915
        wpath = __xmlIOWin32UTF8ToWChar(filename);
916
        if (wpath == NULL) {
917
            xmlFree(fromUri);
918
            return(XML_ERR_NO_MEMORY);
919
        }
920
  fd = _wfopen(wpath, write ? L"wb" : L"rb");
921
        xmlFree(wpath);
922
    }
923
#else
924
0
    fd = fopen(filename, write ? "wb" : "rb");
925
0
#endif /* WIN32 */
926
927
0
    if (fd == NULL) {
928
        /*
929
         * Windows and possibly other platforms return EINVAL
930
         * for invalid filenames.
931
         */
932
0
        if ((errno == ENOENT) || (errno == EINVAL)) {
933
0
            ret = XML_IO_ENOENT;
934
0
        } else {
935
            /*
936
             * This error won't be forwarded to the parser context
937
             * which will report it a second time.
938
             */
939
0
            ret = xmlIOErr(errno);
940
0
        }
941
0
    }
942
943
0
    *out = fd;
944
0
    xmlFree(fromUri);
945
0
    return(ret);
946
0
}
947
948
/**
949
 * @deprecated Internal function, don't use.
950
 *
951
 * @param filename  the URI for matching
952
 * @returns an IO context or NULL in case or failure
953
 */
954
void *
955
0
xmlFileOpen(const char *filename) {
956
0
    void *context;
957
958
0
    xmlFileOpenSafe(filename, 0, &context);
959
0
    return(context);
960
0
}
961
962
/**
963
 * @deprecated Internal function, don't use.
964
 *
965
 * @param context  the I/O context
966
 * @param buffer  where to drop data
967
 * @param len  number of bytes to write
968
 * @returns the number of bytes read or < 0 in case of failure
969
 */
970
int
971
0
xmlFileRead(void * context, char * buffer, int len) {
972
0
    FILE *file = context;
973
0
    size_t bytes;
974
975
0
    if ((context == NULL) || (buffer == NULL))
976
0
        return(-1);
977
978
    /*
979
     * The C standard doesn't mandate that fread sets errno, only
980
     * POSIX does. The Windows documentation isn't really clear.
981
     * Set errno to zero which will be reported as unknown error
982
     * if fread fails without setting errno.
983
     */
984
0
    errno = 0;
985
0
    bytes = fread(buffer, 1, len, file);
986
0
    if ((bytes < (size_t) len) && (ferror(file)))
987
0
        return(-xmlIOErr(errno));
988
989
0
    return(bytes);
990
0
}
991
992
#ifdef LIBXML_OUTPUT_ENABLED
993
/**
994
 * Write `len` bytes from `buffer` to the I/O channel.
995
 *
996
 * @param context  the I/O context
997
 * @param buffer  where to drop data
998
 * @param len  number of bytes to write
999
 * @returns the number of bytes written
1000
 */
1001
static int
1002
0
xmlFileWrite(void *context, const char *buffer, int len) {
1003
0
    FILE *file = context;
1004
0
    size_t bytes;
1005
1006
0
    if ((context == NULL) || (buffer == NULL))
1007
0
        return(-1);
1008
1009
0
    errno = 0;
1010
0
    bytes = fwrite(buffer, 1, len, file);
1011
0
    if (bytes < (size_t) len)
1012
0
        return(-xmlIOErr(errno));
1013
1014
0
    return(len);
1015
0
}
1016
#endif /* LIBXML_OUTPUT_ENABLED */
1017
1018
/**
1019
 * Flush an I/O channel
1020
 *
1021
 * @param context  the I/O context
1022
 */
1023
static int
1024
0
xmlFileFlush (void * context) {
1025
0
    FILE *file = context;
1026
1027
0
    if (file == NULL)
1028
0
        return(-1);
1029
1030
0
    if (fflush(file) != 0)
1031
0
        return(xmlIOErr(errno));
1032
1033
0
    return(XML_ERR_OK);
1034
0
}
1035
1036
/**
1037
 * @deprecated Internal function, don't use.
1038
 *
1039
 * @param context  the I/O context
1040
 * @returns 0 or -1 an error code case of error
1041
 */
1042
int
1043
0
xmlFileClose (void * context) {
1044
0
    FILE *file = context;
1045
1046
0
    if (context == NULL)
1047
0
        return(-1);
1048
1049
0
    if (file == stdin)
1050
0
        return(0);
1051
0
    if ((file == stdout) || (file == stderr))
1052
0
        return(xmlFileFlush(file));
1053
1054
0
    if (fclose(file) != 0)
1055
0
        return(xmlIOErr(errno));
1056
1057
0
    return(0);
1058
0
}
1059
1060
#ifdef LIBXML_OUTPUT_ENABLED
1061
/**
1062
 * Write `len` bytes from `buffer` to the xml buffer
1063
 *
1064
 * @param context  the xmlBuffer
1065
 * @param buffer  the data to write
1066
 * @param len  number of bytes to write
1067
 * @returns the number of bytes written or a negative xmlParserErrors
1068
 * value.
1069
 */
1070
static int
1071
0
xmlBufferWrite (void * context, const char * buffer, int len) {
1072
0
    int ret;
1073
1074
0
    ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1075
0
    if (ret != 0)
1076
0
        return(-XML_ERR_NO_MEMORY);
1077
0
    return(len);
1078
0
}
1079
#endif
1080
1081
#ifdef LIBXML_ZLIB_ENABLED
1082
/************************************************************************
1083
 *                  *
1084
 *    I/O for compressed file accesses      *
1085
 *                  *
1086
 ************************************************************************/
1087
1088
/**
1089
 * Read `len` bytes to `buffer` from the compressed I/O channel.
1090
 *
1091
 * @param context  the I/O context
1092
 * @param buffer  where to drop data
1093
 * @param len  number of bytes to write
1094
 * @returns the number of bytes read.
1095
 */
1096
static int
1097
0
xmlGzfileRead (void * context, char * buffer, int len) {
1098
0
    int ret;
1099
1100
0
    ret = gzread((gzFile) context, &buffer[0], len);
1101
0
    if (ret < 0)
1102
0
        return(-XML_IO_UNKNOWN);
1103
0
    return(ret);
1104
0
}
1105
1106
#ifdef LIBXML_OUTPUT_ENABLED
1107
/**
1108
 * Write `len` bytes from `buffer` to the compressed I/O channel.
1109
 *
1110
 * @param context  the I/O context
1111
 * @param buffer  where to drop data
1112
 * @param len  number of bytes to write
1113
 * @returns the number of bytes written
1114
 */
1115
static int
1116
0
xmlGzfileWrite (void * context, const char * buffer, int len) {
1117
0
    int ret;
1118
1119
0
    ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1120
0
    if (ret < 0)
1121
0
        return(-XML_IO_UNKNOWN);
1122
0
    return(ret);
1123
0
}
1124
#endif /* LIBXML_OUTPUT_ENABLED */
1125
1126
/**
1127
 * Close a compressed I/O channel
1128
 *
1129
 * @param context  the I/O context
1130
 */
1131
static int
1132
0
xmlGzfileClose (void * context) {
1133
0
    if (gzclose((gzFile) context) != Z_OK)
1134
0
        return(XML_IO_UNKNOWN);
1135
0
    return(0);
1136
0
}
1137
#endif /* LIBXML_ZLIB_ENABLED */
1138
1139
/************************************************************************
1140
 *                  *
1141
 *    I/O for compressed file accesses      *
1142
 *                  *
1143
 ************************************************************************/
1144
1145
#ifdef LIBXML_LZMA_ENABLED
1146
1147
#include "private/xzlib.h"
1148
1149
/**
1150
 * Read `len` bytes to `buffer` from the compressed I/O channel.
1151
 *
1152
 * @param context  the I/O context
1153
 * @param buffer  where to drop data
1154
 * @param len  number of bytes to write
1155
 * @returns the number of bytes written
1156
 */
1157
static int
1158
0
xmlXzfileRead (void * context, char * buffer, int len) {
1159
0
    int ret;
1160
1161
0
    ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
1162
0
    if (ret < 0)
1163
0
        return(-XML_IO_UNKNOWN);
1164
0
    return(ret);
1165
0
}
1166
1167
/**
1168
 * Close a compressed I/O channel
1169
 *
1170
 * @param context  the I/O context
1171
 */
1172
static int
1173
0
xmlXzfileClose (void * context) {
1174
0
    if (__libxml2_xzclose((xzFile) context) != LZMA_OK)
1175
0
        return(XML_IO_UNKNOWN);
1176
0
    return(0);
1177
0
}
1178
#endif /* LIBXML_LZMA_ENABLED */
1179
1180
/************************************************************************
1181
 *                  *
1182
 *      Input/output buffers        *
1183
 *                  *
1184
 ************************************************************************/
1185
1186
static int
1187
0
xmlIODefaultMatch(const char *filename ATTRIBUTE_UNUSED) {
1188
0
    return(1);
1189
0
}
1190
1191
#if defined(LIBXML_LZMA_ENABLED) || defined(LIBXML_ZLIB_ENABLED)
1192
1193
#ifdef _WIN32
1194
typedef __int64 xmlFileOffset;
1195
#else
1196
typedef off_t xmlFileOffset;
1197
#endif
1198
1199
static xmlFileOffset
1200
0
xmlSeek(int fd, xmlFileOffset offset, int whence) {
1201
#ifdef _WIN32
1202
    HANDLE h = (HANDLE) _get_osfhandle(fd);
1203
1204
    /*
1205
     * Windows doesn't return an error on unseekable files like pipes.
1206
     */
1207
    if (h != INVALID_HANDLE_VALUE && GetFileType(h) != FILE_TYPE_DISK)
1208
        return -1;
1209
    return _lseeki64(fd, offset, whence);
1210
#else
1211
0
    return lseek(fd, offset, whence);
1212
0
#endif
1213
0
}
1214
1215
#endif /* defined(LIBXML_LZMA_ENABLED) || defined(LIBXML_ZLIB_ENABLED) */
1216
1217
/**
1218
 * Update the buffer to read from `fd`. Supports the XML_INPUT_UNZIP
1219
 * flag.
1220
 *
1221
 * @param buf  parser input buffer
1222
 * @param fd  file descriptor
1223
 * @param flags  flags
1224
 * @returns an xmlParserErrors code.
1225
 */
1226
xmlParserErrors
1227
xmlInputFromFd(xmlParserInputBuffer *buf, int fd,
1228
0
               xmlParserInputFlags flags) {
1229
0
    xmlFdIOCtxt *fdctxt;
1230
0
    int copy;
1231
1232
0
    (void) flags;
1233
1234
0
#ifdef LIBXML_LZMA_ENABLED
1235
0
    if (flags & XML_INPUT_UNZIP) {
1236
0
        xzFile xzStream;
1237
0
        xmlFileOffset pos;
1238
1239
0
        pos = xmlSeek(fd, 0, SEEK_CUR);
1240
1241
0
        copy = dup(fd);
1242
0
        if (copy == -1)
1243
0
            return(xmlIOErr(errno));
1244
1245
0
        xzStream = __libxml2_xzdopen("?", copy, "rb");
1246
1247
0
        if (xzStream == NULL) {
1248
0
            close(copy);
1249
0
        } else {
1250
0
            int compressed = (__libxml2_xzcompressed(xzStream) > 0);
1251
1252
0
            if ((compressed) ||
1253
                /* Try to rewind if not gzip compressed */
1254
0
                (pos < 0) ||
1255
0
                (xmlSeek(fd, pos, SEEK_SET) < 0)) {
1256
                /*
1257
                 * If a file isn't seekable, we pipe uncompressed
1258
                 * input through xzlib.
1259
                 */
1260
0
                buf->context = xzStream;
1261
0
                buf->readcallback = xmlXzfileRead;
1262
0
                buf->closecallback = xmlXzfileClose;
1263
0
                buf->compressed = compressed;
1264
1265
0
                return(XML_ERR_OK);
1266
0
            }
1267
1268
0
            xmlXzfileClose(xzStream);
1269
0
        }
1270
0
    }
1271
0
#endif /* LIBXML_LZMA_ENABLED */
1272
1273
0
#ifdef LIBXML_ZLIB_ENABLED
1274
0
    if (flags & XML_INPUT_UNZIP) {
1275
0
        gzFile gzStream;
1276
0
        xmlFileOffset pos;
1277
1278
0
        pos = xmlSeek(fd, 0, SEEK_CUR);
1279
1280
0
        copy = dup(fd);
1281
0
        if (copy == -1)
1282
0
            return(xmlIOErr(errno));
1283
1284
0
        gzStream = gzdopen(copy, "rb");
1285
1286
0
        if (gzStream == NULL) {
1287
0
            close(copy);
1288
0
        } else {
1289
0
            int compressed = (gzdirect(gzStream) == 0);
1290
1291
0
            if ((compressed) ||
1292
                /* Try to rewind if not gzip compressed */
1293
0
                (pos < 0) ||
1294
0
                (xmlSeek(fd, pos, SEEK_SET) < 0)) {
1295
                /*
1296
                 * If a file isn't seekable, we pipe uncompressed
1297
                 * input through zlib.
1298
                 */
1299
0
                buf->context = gzStream;
1300
0
                buf->readcallback = xmlGzfileRead;
1301
0
                buf->closecallback = xmlGzfileClose;
1302
0
                buf->compressed = compressed;
1303
1304
0
                return(XML_ERR_OK);
1305
0
            }
1306
1307
0
            xmlGzfileClose(gzStream);
1308
0
        }
1309
0
    }
1310
0
#endif /* LIBXML_ZLIB_ENABLED */
1311
1312
0
    copy = dup(fd);
1313
0
    if (copy == -1)
1314
0
        return(xmlIOErr(errno));
1315
1316
0
    fdctxt = xmlMalloc(sizeof(*fdctxt));
1317
0
    if (fdctxt == NULL) {
1318
0
        close(copy);
1319
0
        return(XML_ERR_NO_MEMORY);
1320
0
    }
1321
0
    fdctxt->fd = copy;
1322
1323
0
    buf->context = fdctxt;
1324
0
    buf->readcallback = xmlFdRead;
1325
0
    buf->closecallback = xmlFdClose;
1326
1327
0
    return(XML_ERR_OK);
1328
0
}
1329
1330
#ifdef LIBXML_OUTPUT_ENABLED
1331
/**
1332
 * @param buf  input buffer to be filled
1333
 * @param filename  filename or URI
1334
 * @param compression  compression level or 0
1335
 * @returns an xmlParserErrors code.
1336
 */
1337
static xmlParserErrors
1338
xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename,
1339
0
                     int compression) {
1340
0
    xmlFdIOCtxt *fdctxt;
1341
0
    int fd;
1342
1343
0
    (void) compression;
1344
1345
0
    if (!strcmp(filename, "-")) {
1346
0
        fd = dup(STDOUT_FILENO);
1347
1348
0
        if (fd < 0)
1349
0
            return(xmlIOErr(errno));
1350
0
    } else {
1351
0
        int ret;
1352
1353
0
        ret = xmlFdOpen(filename, /* write */ 1, &fd);
1354
0
        if (ret != XML_ERR_OK)
1355
0
            return(ret);
1356
0
    }
1357
1358
0
#ifdef LIBXML_ZLIB_ENABLED
1359
0
    if ((compression > 0) && (compression <= 9)) {
1360
0
        gzFile gzStream;
1361
0
        char mode[15];
1362
1363
0
        snprintf(mode, sizeof(mode), "wb%d", compression);
1364
0
        gzStream = gzdopen(fd, mode);
1365
1366
0
        if (gzStream == NULL) {
1367
0
            close(fd);
1368
0
            return(XML_IO_UNKNOWN);
1369
0
        }
1370
1371
0
        buf->context = gzStream;
1372
0
        buf->writecallback = xmlGzfileWrite;
1373
0
        buf->closecallback = xmlGzfileClose;
1374
1375
0
        return(XML_ERR_OK);
1376
0
    }
1377
0
#endif /* LIBXML_ZLIB_ENABLED */
1378
1379
0
    fdctxt = xmlMalloc(sizeof(*fdctxt));
1380
0
    if (fdctxt == NULL) {
1381
0
        close(fd);
1382
0
        return(XML_ERR_NO_MEMORY);
1383
0
    }
1384
0
    fdctxt->fd = fd;
1385
1386
0
    buf->context = fdctxt;
1387
0
    buf->writecallback = xmlFdWrite;
1388
0
    buf->closecallback = xmlFdClose;
1389
0
    return(XML_ERR_OK);
1390
0
}
1391
#endif
1392
1393
/**
1394
 * Create a buffered parser input for progressive parsing.
1395
 *
1396
 * @deprecated Use xmlNewInputFrom*.
1397
 *
1398
 * The encoding argument is deprecated and should be set to
1399
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1400
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
1401
 *
1402
 * @param enc  the charset encoding if known (deprecated)
1403
 * @returns the new parser input or NULL
1404
 */
1405
xmlParserInputBuffer *
1406
27.4k
xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1407
27.4k
    xmlParserInputBufferPtr ret;
1408
1409
27.4k
    ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1410
27.4k
    if (ret == NULL) {
1411
0
  return(NULL);
1412
0
    }
1413
27.4k
    memset(ret, 0, sizeof(xmlParserInputBuffer));
1414
27.4k
    ret->buffer = xmlBufCreate(XML_IO_BUFFER_SIZE);
1415
27.4k
    if (ret->buffer == NULL) {
1416
0
        xmlFree(ret);
1417
0
  return(NULL);
1418
0
    }
1419
27.4k
    if (enc != XML_CHAR_ENCODING_NONE) {
1420
0
        if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != XML_ERR_OK) {
1421
            /* We can't handle errors properly here. */
1422
0
            xmlFreeParserInputBuffer(ret);
1423
0
            return(NULL);
1424
0
        }
1425
0
    }
1426
27.4k
    if (ret->encoder != NULL)
1427
0
        ret->raw = xmlBufCreate(XML_IO_BUFFER_SIZE);
1428
27.4k
    else
1429
27.4k
        ret->raw = NULL;
1430
27.4k
    ret->readcallback = NULL;
1431
27.4k
    ret->closecallback = NULL;
1432
27.4k
    ret->context = NULL;
1433
27.4k
    ret->compressed = -1;
1434
27.4k
    ret->rawconsumed = 0;
1435
1436
27.4k
    return(ret);
1437
27.4k
}
1438
1439
#ifdef LIBXML_OUTPUT_ENABLED
1440
/**
1441
 * Create a buffered parser output
1442
 *
1443
 * Consumes `encoder` but not in error case.
1444
 *
1445
 * @param encoder  the encoding converter or NULL
1446
 * @returns the new parser output or NULL
1447
 */
1448
xmlOutputBuffer *
1449
0
xmlAllocOutputBuffer(xmlCharEncodingHandler *encoder) {
1450
0
    xmlOutputBufferPtr ret;
1451
1452
0
    ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1453
0
    if (ret == NULL) {
1454
0
  return(NULL);
1455
0
    }
1456
0
    memset(ret, 0, sizeof(xmlOutputBuffer));
1457
0
    ret->buffer = xmlBufCreate(MINLEN);
1458
0
    if (ret->buffer == NULL) {
1459
0
        xmlFree(ret);
1460
0
  return(NULL);
1461
0
    }
1462
1463
0
    ret->encoder = encoder;
1464
0
    if (encoder != NULL) {
1465
0
        ret->conv = xmlBufCreate(MINLEN);
1466
0
  if (ret->conv == NULL) {
1467
0
            xmlBufFree(ret->buffer);
1468
0
            xmlFree(ret);
1469
0
      return(NULL);
1470
0
  }
1471
1472
  /*
1473
   * This call is designed to initiate the encoder state
1474
   */
1475
0
  xmlCharEncOutput(ret, 1);
1476
0
    } else
1477
0
        ret->conv = NULL;
1478
0
    ret->writecallback = NULL;
1479
0
    ret->closecallback = NULL;
1480
0
    ret->context = NULL;
1481
0
    ret->written = 0;
1482
1483
0
    return(ret);
1484
0
}
1485
#endif /* LIBXML_OUTPUT_ENABLED */
1486
1487
/**
1488
 * Free up the memory used by a buffered parser input
1489
 *
1490
 * @param in  a buffered parser input
1491
 */
1492
void
1493
45.1k
xmlFreeParserInputBuffer(xmlParserInputBuffer *in) {
1494
45.1k
    if (in == NULL) return;
1495
1496
45.1k
    if (in->raw) {
1497
4.95k
        xmlBufFree(in->raw);
1498
4.95k
  in->raw = NULL;
1499
4.95k
    }
1500
45.1k
    if (in->encoder != NULL) {
1501
4.95k
        xmlCharEncCloseFunc(in->encoder);
1502
4.95k
    }
1503
45.1k
    if (in->closecallback != NULL) {
1504
0
  in->closecallback(in->context);
1505
0
    }
1506
45.1k
    if (in->buffer != NULL) {
1507
45.1k
        xmlBufFree(in->buffer);
1508
45.1k
  in->buffer = NULL;
1509
45.1k
    }
1510
1511
45.1k
    xmlFree(in);
1512
45.1k
}
1513
1514
#ifdef LIBXML_OUTPUT_ENABLED
1515
/**
1516
 * flushes and close the output I/O channel
1517
 * and free up all the associated resources
1518
 *
1519
 * @param out  a buffered output
1520
 * @returns the number of byte written or a negative xmlParserErrors
1521
 * code in case of error.
1522
 */
1523
int
1524
xmlOutputBufferClose(xmlOutputBuffer *out)
1525
0
{
1526
0
    int ret;
1527
1528
0
    if (out == NULL)
1529
0
        return (-1);
1530
1531
0
    if (out->writecallback != NULL)
1532
0
        xmlOutputBufferFlush(out);
1533
1534
0
    if (out->closecallback != NULL) {
1535
0
        int code = out->closecallback(out->context);
1536
1537
0
        if ((code != XML_ERR_OK) &&
1538
0
            (!xmlIsCatastrophicError(XML_ERR_FATAL, out->error))) {
1539
0
            if (code < 0)
1540
0
                out->error = XML_IO_UNKNOWN;
1541
0
            else
1542
0
                out->error = code;
1543
0
        }
1544
0
    }
1545
1546
0
    if (out->error != XML_ERR_OK)
1547
0
        ret = -out->error;
1548
0
    else
1549
0
        ret = out->written;
1550
1551
0
    if (out->conv) {
1552
0
        xmlBufFree(out->conv);
1553
0
        out->conv = NULL;
1554
0
    }
1555
0
    if (out->encoder != NULL) {
1556
0
        xmlCharEncCloseFunc(out->encoder);
1557
0
    }
1558
0
    if (out->buffer != NULL) {
1559
0
        xmlBufFree(out->buffer);
1560
0
        out->buffer = NULL;
1561
0
    }
1562
1563
0
    xmlFree(out);
1564
1565
0
    return(ret);
1566
0
}
1567
#endif /* LIBXML_OUTPUT_ENABLED */
1568
1569
/**
1570
 * @param URI  the filename or URI
1571
 * @param enc  encoding enum (deprecated)
1572
 * @param flags  XML_INPUT flags
1573
 * @param out  pointer to resulting input buffer
1574
 * @returns an xmlParserErrors code.
1575
 */
1576
xmlParserErrors
1577
xmlParserInputBufferCreateUrl(const char *URI, xmlCharEncoding enc,
1578
                              xmlParserInputFlags flags,
1579
0
                              xmlParserInputBuffer **out) {
1580
0
    xmlParserInputBufferPtr buf;
1581
0
    xmlParserErrors ret;
1582
0
    int i;
1583
1584
0
    xmlInitParser();
1585
1586
0
    *out = NULL;
1587
0
    if (URI == NULL)
1588
0
        return(XML_ERR_ARGUMENT);
1589
1590
    /*
1591
     * Allocate the Input buffer front-end.
1592
     */
1593
0
    buf = xmlAllocParserInputBuffer(enc);
1594
0
    if (buf == NULL)
1595
0
        return(XML_ERR_NO_MEMORY);
1596
1597
    /*
1598
     * Try to find one of the input accept method accepting that scheme
1599
     * Go in reverse to give precedence to user defined handlers.
1600
     */
1601
0
    ret = XML_IO_ENOENT;
1602
0
    for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
1603
0
        xmlInputCallback *cb = &xmlInputCallbackTable[i];
1604
1605
0
        if (cb->matchcallback == xmlIODefaultMatch) {
1606
0
            int fd;
1607
1608
0
            ret = xmlFdOpen(URI, 0, &fd);
1609
1610
0
            if (ret == XML_ERR_OK) {
1611
0
                ret = xmlInputFromFd(buf, fd, flags);
1612
0
                close(fd);
1613
0
                break;
1614
0
            } else if (ret != XML_IO_ENOENT) {
1615
0
                break;
1616
0
            }
1617
0
        } else if ((cb->matchcallback != NULL) &&
1618
0
                   (cb->matchcallback(URI) != 0)) {
1619
0
            buf->context = cb->opencallback(URI);
1620
0
            if (buf->context != NULL) {
1621
0
                buf->readcallback = cb->readcallback;
1622
0
                buf->closecallback = cb->closecallback;
1623
0
                ret = XML_ERR_OK;
1624
0
                break;
1625
0
            }
1626
0
        }
1627
0
    }
1628
0
    if (ret != XML_ERR_OK) {
1629
0
        xmlFreeParserInputBuffer(buf);
1630
0
        *out = NULL;
1631
0
  return(ret);
1632
0
    }
1633
1634
0
    *out = buf;
1635
0
    return(ret);
1636
0
}
1637
1638
/**
1639
 * Create a buffered parser input for the progressive parsing of a file
1640
 * Automatic support for ZLIB/Compress compressed document is provided
1641
 * by default if found at compile-time.
1642
 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1643
 *
1644
 * Internal implementation, never uses the callback installed with
1645
 * #xmlParserInputBufferCreateFilenameDefault.
1646
 *
1647
 * @deprecated Use #xmlNewInputFromUrl.
1648
 *
1649
 * @param URI  a C string containing the URI or filename
1650
 * @param enc  the charset encoding if known
1651
 * @returns the new parser input or NULL
1652
 */
1653
xmlParserInputBuffer *
1654
0
__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1655
0
    xmlParserInputBufferPtr ret;
1656
1657
0
    xmlParserInputBufferCreateUrl(URI, enc, 0, &ret);
1658
0
    return(ret);
1659
0
}
1660
1661
/**
1662
 * Create a buffered parser input for the progressive parsing of a file
1663
 * Automatic support for ZLIB/Compress compressed document is provided
1664
 * by default if found at compile-time.
1665
 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1666
 *
1667
 * Allows the actual function to be overridden with
1668
 * #xmlParserInputBufferCreateFilenameDefault.
1669
 *
1670
 * @deprecated Use #xmlNewInputFromUrl.
1671
 *
1672
 * @param URI  a C string containing the URI or filename
1673
 * @param enc  the charset encoding if known
1674
 * @returns the new parser input or NULL
1675
 */
1676
xmlParserInputBuffer *
1677
0
xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1678
0
    xmlParserInputBufferPtr ret;
1679
0
    xmlParserErrors code;
1680
1681
0
    if (xmlParserInputBufferCreateFilenameValue != NULL)
1682
0
        return(xmlParserInputBufferCreateFilenameValue(URI, enc));
1683
1684
0
    code = xmlParserInputBufferCreateUrl(URI, enc, 0, &ret);
1685
1686
    /*
1687
     * xmlParserInputBufferCreateFilename has no way to return
1688
     * the kind of error although it really is crucial.
1689
     * All we can do is to set the global error.
1690
     */
1691
0
    if ((code != XML_ERR_OK) && (code != XML_IO_ENOENT)) {
1692
0
        if (xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_IO, code,
1693
0
                          XML_ERR_ERROR, URI, 0, NULL, NULL, NULL, 0, 0,
1694
0
                          "Failed to open file\n") < 0)
1695
0
            xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_IO, NULL);
1696
0
    }
1697
1698
0
    return(ret);
1699
0
}
1700
1701
#ifdef LIBXML_OUTPUT_ENABLED
1702
/**
1703
 * Create a buffered  output for the progressive saving of a file
1704
 * If filename is `"-"` then we use stdout as the output.
1705
 * Automatic support for ZLIB/Compress compressed document is provided
1706
 * by default if found at compile-time.
1707
 *
1708
 * Consumes `encoder` but not in error case.
1709
 *
1710
 * Internal implementation, never uses the callback installed with
1711
 * #xmlOutputBufferCreateFilenameDefault.
1712
 *
1713
 * @param URI  a C string containing the URI or filename
1714
 * @param encoder  the encoding converter or NULL
1715
 * @param compression  the compression ration (0 none, 9 max).
1716
 * @returns the new output or NULL
1717
 */
1718
xmlOutputBuffer *
1719
__xmlOutputBufferCreateFilename(const char *URI,
1720
                              xmlCharEncodingHandler *encoder,
1721
0
                              int compression) {
1722
0
    xmlOutputBufferPtr ret = NULL;
1723
0
    xmlURIPtr puri;
1724
0
    int i = 0;
1725
0
    char *unescaped = NULL;
1726
1727
0
    xmlInitParser();
1728
1729
0
    if (URI == NULL)
1730
0
        goto error;
1731
1732
0
    puri = xmlParseURI(URI);
1733
0
    if (puri != NULL) {
1734
        /*
1735
         * try to limit the damages of the URI unescaping code.
1736
         */
1737
0
        if (puri->scheme == NULL) {
1738
0
            unescaped = xmlURIUnescapeString(URI, 0, NULL);
1739
0
            if (unescaped == NULL) {
1740
0
                xmlFreeURI(puri);
1741
0
                goto error;
1742
0
            }
1743
0
            URI = unescaped;
1744
0
        }
1745
0
        xmlFreeURI(puri);
1746
0
    }
1747
1748
    /*
1749
     * Allocate the Output buffer front-end.
1750
     */
1751
0
    ret = xmlAllocOutputBuffer(encoder);
1752
0
    if (ret == NULL)
1753
0
        goto error;
1754
1755
    /*
1756
     * Try to find one of the output accept method accepting that scheme
1757
     * Go in reverse to give precedence to user defined handlers.
1758
     */
1759
0
    for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
1760
0
        xmlOutputCallback *cb = &xmlOutputCallbackTable[i];
1761
0
        xmlParserErrors code;
1762
1763
0
        if (cb->matchcallback == xmlIODefaultMatch) {
1764
0
            code = xmlOutputDefaultOpen(ret, URI, compression);
1765
            /* TODO: Handle other errors */
1766
0
            if (code == XML_ERR_OK)
1767
0
                break;
1768
0
        } else if ((cb->matchcallback != NULL) &&
1769
0
                   (cb->matchcallback(URI) != 0)) {
1770
0
            ret->context = cb->opencallback(URI);
1771
0
            if (ret->context != NULL) {
1772
0
                ret->writecallback = cb->writecallback;
1773
0
                ret->closecallback = cb->closecallback;
1774
0
                break;
1775
0
            }
1776
0
        }
1777
0
    }
1778
1779
0
    if (ret->context == NULL) {
1780
        /* Don't free encoder */
1781
0
        ret->encoder = NULL;
1782
0
        xmlOutputBufferClose(ret);
1783
0
  ret = NULL;
1784
0
    }
1785
1786
0
error:
1787
0
    xmlFree(unescaped);
1788
0
    return(ret);
1789
0
}
1790
1791
/**
1792
 * Create a buffered  output for the progressive saving of a file
1793
 * If filename is `"-"` then we use stdout as the output.
1794
 * Automatic support for ZLIB/Compress compressed document is provided
1795
 * by default if found at compile-time.
1796
 *
1797
 * Consumes `encoder` but not in error case.
1798
 *
1799
 * Allows the actual function to be overridden with
1800
 * #xmlOutputBufferCreateFilenameDefault.
1801
 *
1802
 * @param URI  a C string containing the URI or filename
1803
 * @param encoder  the encoding converter or NULL
1804
 * @param compression  the compression ration (0 none, 9 max).
1805
 * @returns the new output or NULL
1806
 */
1807
xmlOutputBuffer *
1808
xmlOutputBufferCreateFilename(const char *URI,
1809
                              xmlCharEncodingHandler *encoder,
1810
0
                              int compression ATTRIBUTE_UNUSED) {
1811
0
    if ((xmlOutputBufferCreateFilenameValue)) {
1812
0
    return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
1813
0
  }
1814
0
  return __xmlOutputBufferCreateFilename(URI, encoder, compression);
1815
0
}
1816
#endif /* LIBXML_OUTPUT_ENABLED */
1817
1818
/**
1819
 * Create a buffered parser input for the progressive parsing of a FILE *
1820
 * buffered C I/O
1821
 *
1822
 * @deprecated Don't use.
1823
 *
1824
 * The encoding argument is deprecated and should be set to
1825
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1826
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
1827
 *
1828
 * @param file  a FILE*
1829
 * @param enc  the charset encoding if known (deprecated)
1830
 * @returns the new parser input or NULL
1831
 */
1832
xmlParserInputBuffer *
1833
0
xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1834
0
    xmlParserInputBufferPtr ret;
1835
1836
0
    if (file == NULL) return(NULL);
1837
1838
0
    ret = xmlAllocParserInputBuffer(enc);
1839
0
    if (ret != NULL) {
1840
0
        ret->context = file;
1841
0
  ret->readcallback = xmlFileRead;
1842
0
  ret->closecallback = NULL;
1843
0
    }
1844
1845
0
    return(ret);
1846
0
}
1847
1848
#ifdef LIBXML_OUTPUT_ENABLED
1849
/**
1850
 * Create a buffered output for the progressive saving to a `FILE *`
1851
 * buffered C I/O.
1852
 *
1853
 * Consumes `encoder` but not in error case.
1854
 *
1855
 * @param file  a `FILE *`
1856
 * @param encoder  the encoding converter or NULL
1857
 * @returns the new parser output or NULL
1858
 */
1859
xmlOutputBuffer *
1860
0
xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandler *encoder) {
1861
0
    xmlOutputBufferPtr ret;
1862
1863
0
    if (file == NULL) {
1864
0
        return(NULL);
1865
0
    }
1866
1867
0
    ret = xmlAllocOutputBuffer(encoder);
1868
0
    if (ret != NULL) {
1869
0
        ret->context = file;
1870
0
  ret->writecallback = xmlFileWrite;
1871
0
  ret->closecallback = xmlFileFlush;
1872
0
    }
1873
1874
0
    return(ret);
1875
0
}
1876
1877
/**
1878
 * Create a buffered output for the progressive saving to a xmlBuffer
1879
 *
1880
 * Consumes `encoder` but not in error case.
1881
 *
1882
 * @param buffer  a xmlBuffer
1883
 * @param encoder  the encoding converter or NULL
1884
 * @returns the new parser output or NULL
1885
 */
1886
xmlOutputBuffer *
1887
xmlOutputBufferCreateBuffer(xmlBuffer *buffer,
1888
0
                            xmlCharEncodingHandler *encoder) {
1889
0
    xmlOutputBufferPtr ret;
1890
1891
0
    if (buffer == NULL) {
1892
0
        return(NULL);
1893
0
    }
1894
1895
0
    ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
1896
0
                                  encoder);
1897
1898
0
    return(ret);
1899
0
}
1900
1901
/**
1902
 * Gives a pointer to the data currently held in the output buffer
1903
 *
1904
 * @param out  an xmlOutputBuffer
1905
 * @returns a pointer to the data or NULL in case of error
1906
 */
1907
const xmlChar *
1908
0
xmlOutputBufferGetContent(xmlOutputBuffer *out) {
1909
0
    if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
1910
0
        return(NULL);
1911
1912
0
    return(xmlBufContent(out->buffer));
1913
0
}
1914
1915
/**
1916
 * Gives the length of the data currently held in the output buffer
1917
 *
1918
 * @param out  an xmlOutputBuffer
1919
 * @returns 0 in case or error or no data is held, the size otherwise
1920
 */
1921
size_t
1922
0
xmlOutputBufferGetSize(xmlOutputBuffer *out) {
1923
0
    if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
1924
0
        return(0);
1925
1926
0
    return(xmlBufUse(out->buffer));
1927
0
}
1928
1929
1930
#endif /* LIBXML_OUTPUT_ENABLED */
1931
1932
/**
1933
 * Create a buffered parser input for the progressive parsing for the input
1934
 * from a file descriptor
1935
 *
1936
 * @deprecated Use #xmlNewInputFromFd.
1937
 *
1938
 * The encoding argument is deprecated and should be set to
1939
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1940
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
1941
 *
1942
 * @param fd  a file descriptor number
1943
 * @param enc  the charset encoding if known (deprecated)
1944
 * @returns the new parser input or NULL
1945
 */
1946
xmlParserInputBuffer *
1947
0
xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1948
0
    xmlParserInputBufferPtr ret;
1949
1950
0
    if (fd < 0) return(NULL);
1951
1952
0
    ret = xmlAllocParserInputBuffer(enc);
1953
0
    if (ret != NULL) {
1954
0
        xmlFdIOCtxt *fdctxt;
1955
1956
0
        fdctxt = xmlMalloc(sizeof(*fdctxt));
1957
0
        if (fdctxt == NULL) {
1958
0
            return(NULL);
1959
0
        }
1960
0
        fdctxt->fd = fd;
1961
1962
0
        ret->context = fdctxt;
1963
0
  ret->readcallback = xmlFdRead;
1964
0
        ret->closecallback = xmlFdFree;
1965
0
    }
1966
1967
0
    return(ret);
1968
0
}
1969
1970
typedef struct {
1971
    const char *cur;
1972
    size_t size;
1973
} xmlMemIOCtxt;
1974
1975
static int
1976
0
xmlMemRead(void *vctxt, char *buf, int size) {
1977
0
    xmlMemIOCtxt *ctxt = vctxt;
1978
1979
0
    if ((size_t) size > ctxt->size)
1980
0
        size = ctxt->size;
1981
1982
0
    memcpy(buf, ctxt->cur, size);
1983
0
    ctxt->cur += size;
1984
0
    ctxt->size -= size;
1985
1986
0
    return size;
1987
0
}
1988
1989
static int
1990
0
xmlMemClose(void *vctxt) {
1991
0
    xmlMemIOCtxt *ctxt = vctxt;
1992
1993
0
    xmlFree(ctxt);
1994
0
    return(0);
1995
0
}
1996
1997
/**
1998
 * Create an input buffer for memory.
1999
 *
2000
 * @param mem  memory buffer
2001
 * @param size  size of buffer
2002
 * @param flags  flags
2003
 * @param enc  the charset encoding if known (deprecated)
2004
 * @returns the new input buffer or NULL.
2005
 */
2006
xmlParserInputBuffer *
2007
xmlNewInputBufferMemory(const void *mem, size_t size,
2008
0
                        xmlParserInputFlags flags, xmlCharEncoding enc) {
2009
0
    xmlParserInputBufferPtr ret;
2010
2011
0
    if ((flags & XML_INPUT_BUF_STATIC) &&
2012
0
        ((flags & XML_INPUT_BUF_ZERO_TERMINATED) == 0)) {
2013
0
        xmlMemIOCtxt *ctxt;
2014
2015
        /*
2016
         * Static buffer without zero terminator.
2017
         * Stream memory to avoid a copy.
2018
         */
2019
0
        ret = xmlAllocParserInputBuffer(enc);
2020
0
        if (ret == NULL)
2021
0
            return(NULL);
2022
2023
0
        ctxt = xmlMalloc(sizeof(*ctxt));
2024
0
        if (ctxt == NULL) {
2025
0
            xmlFreeParserInputBuffer(ret);
2026
0
            return(NULL);
2027
0
        }
2028
2029
0
        ctxt->cur = mem;
2030
0
        ctxt->size = size;
2031
2032
0
        ret->context = ctxt;
2033
0
        ret->readcallback = xmlMemRead;
2034
0
        ret->closecallback = xmlMemClose;
2035
0
    } else {
2036
0
        ret = xmlMalloc(sizeof(*ret));
2037
0
        if (ret == NULL)
2038
0
            return(NULL);
2039
0
        memset(ret, 0, sizeof(xmlParserInputBuffer));
2040
0
        ret->compressed = -1;
2041
2042
0
        ret->buffer = xmlBufCreateMem((const xmlChar *) mem, size,
2043
0
                                      (flags & XML_INPUT_BUF_STATIC ? 1 : 0));
2044
0
        if (ret->buffer == NULL) {
2045
0
            xmlFree(ret);
2046
0
            return(NULL);
2047
0
        }
2048
0
    }
2049
2050
0
    return(ret);
2051
0
}
2052
2053
/**
2054
 * Create a parser input buffer for parsing from a memory area.
2055
 *
2056
 * @deprecated Use #xmlNewInputFromMemory.
2057
 *
2058
 * This function makes a copy of the whole input buffer. If you are sure
2059
 * that the contents of the buffer will remain valid until the document
2060
 * was parsed, you can avoid the copy by using
2061
 * #xmlParserInputBufferCreateStatic.
2062
 *
2063
 * The encoding argument is deprecated and should be set to
2064
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
2065
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
2066
 *
2067
 * @param mem  the memory input
2068
 * @param size  the length of the memory block
2069
 * @param enc  the charset encoding if known (deprecated)
2070
 * @returns the new parser input or NULL in case of error.
2071
 */
2072
xmlParserInputBuffer *
2073
0
xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2074
0
    if ((mem == NULL) || (size < 0))
2075
0
        return(NULL);
2076
2077
0
    return(xmlNewInputBufferMemory(mem, size, 0, enc));
2078
0
}
2079
2080
/**
2081
 * Create a parser input buffer for parsing from a memory area.
2082
 *
2083
 * @deprecated Use #xmlNewInputFromMemory.
2084
 *
2085
 * This functions assumes that the contents of the input buffer remain
2086
 * valid until the document was parsed. Use #xmlParserInputBufferCreateMem
2087
 * otherwise.
2088
 *
2089
 * The encoding argument is deprecated and should be set to
2090
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
2091
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
2092
 *
2093
 * @param mem  the memory input
2094
 * @param size  the length of the memory block
2095
 * @param enc  the charset encoding if known
2096
 * @returns the new parser input or NULL in case of error.
2097
 */
2098
xmlParserInputBuffer *
2099
xmlParserInputBufferCreateStatic(const char *mem, int size,
2100
0
                                 xmlCharEncoding enc) {
2101
0
    if ((mem == NULL) || (size < 0))
2102
0
        return(NULL);
2103
2104
0
    return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc));
2105
0
}
2106
2107
/**
2108
 * Create an input buffer for a null-terminated C string.
2109
 *
2110
 * @deprecated Use #xmlNewInputFromString.
2111
 *
2112
 * @param str  C string
2113
 * @param flags  flags
2114
 * @returns the new input buffer or NULL.
2115
 */
2116
xmlParserInputBuffer *
2117
17.7k
xmlNewInputBufferString(const char *str, xmlParserInputFlags flags) {
2118
17.7k
    xmlParserInputBufferPtr ret;
2119
2120
17.7k
    ret = xmlMalloc(sizeof(*ret));
2121
17.7k
    if (ret == NULL)
2122
0
  return(NULL);
2123
17.7k
    memset(ret, 0, sizeof(xmlParserInputBuffer));
2124
17.7k
    ret->compressed = -1;
2125
2126
17.7k
    ret->buffer = xmlBufCreateMem((const xmlChar *) str, strlen(str),
2127
17.7k
                                  (flags & XML_INPUT_BUF_STATIC ? 1 : 0));
2128
17.7k
    if (ret->buffer == NULL) {
2129
0
        xmlFree(ret);
2130
0
  return(NULL);
2131
0
    }
2132
2133
17.7k
    return(ret);
2134
17.7k
}
2135
2136
#ifdef LIBXML_OUTPUT_ENABLED
2137
/**
2138
 * Create a buffered output for the progressive saving
2139
 * to a file descriptor
2140
 *
2141
 * Consumes `encoder` but not in error case.
2142
 *
2143
 * @param fd  a file descriptor number
2144
 * @param encoder  the encoding converter or NULL
2145
 * @returns the new parser output or NULL
2146
 */
2147
xmlOutputBuffer *
2148
0
xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandler *encoder) {
2149
0
    xmlOutputBufferPtr ret;
2150
2151
0
    if (fd < 0) {
2152
0
        return(NULL);
2153
0
    }
2154
2155
0
    ret = xmlAllocOutputBuffer(encoder);
2156
0
    if (ret != NULL) {
2157
0
        xmlFdIOCtxt *fdctxt;
2158
2159
0
        fdctxt = xmlMalloc(sizeof(*fdctxt));
2160
0
        if (fdctxt == NULL) {
2161
0
            return(NULL);
2162
0
        }
2163
0
        fdctxt->fd = fd;
2164
2165
0
        ret->context = fdctxt;
2166
0
  ret->writecallback = xmlFdWrite;
2167
0
        ret->closecallback = xmlFdFree;
2168
0
    }
2169
2170
0
    return(ret);
2171
0
}
2172
#endif /* LIBXML_OUTPUT_ENABLED */
2173
2174
/**
2175
 * Create a buffered parser input for the progressive parsing for the input
2176
 * from an I/O handler
2177
 *
2178
 * @deprecated Use #xmlNewInputFromIO.
2179
 *
2180
 * The encoding argument is deprecated and should be set to
2181
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
2182
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
2183
 *
2184
 * @param ioread  an I/O read function
2185
 * @param ioclose  an I/O close function
2186
 * @param ioctx  an I/O handler
2187
 * @param enc  the charset encoding if known (deprecated)
2188
 * @returns the new parser input or NULL
2189
 */
2190
xmlParserInputBuffer *
2191
xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
2192
0
   xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
2193
0
    xmlParserInputBufferPtr ret;
2194
2195
0
    if (ioread == NULL) return(NULL);
2196
2197
0
    ret = xmlAllocParserInputBuffer(enc);
2198
0
    if (ret != NULL) {
2199
0
        ret->context = (void *) ioctx;
2200
0
  ret->readcallback = ioread;
2201
0
  ret->closecallback = ioclose;
2202
0
    }
2203
2204
0
    return(ret);
2205
0
}
2206
2207
#ifdef LIBXML_OUTPUT_ENABLED
2208
/**
2209
 * Create a buffered output for the progressive saving
2210
 * to an I/O handler
2211
 *
2212
 * Consumes `encoder` but not in error case.
2213
 *
2214
 * @param iowrite  an I/O write function
2215
 * @param ioclose  an I/O close function
2216
 * @param ioctx  an I/O handler
2217
 * @param encoder  the charset encoding if known
2218
 * @returns the new parser output or NULL
2219
 */
2220
xmlOutputBuffer *
2221
xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite,
2222
   xmlOutputCloseCallback  ioclose, void *ioctx,
2223
0
   xmlCharEncodingHandler *encoder) {
2224
0
    xmlOutputBufferPtr ret;
2225
2226
0
    if (iowrite == NULL) {
2227
0
        return(NULL);
2228
0
    }
2229
2230
0
    ret = xmlAllocOutputBuffer(encoder);
2231
0
    if (ret != NULL) {
2232
0
        ret->context = (void *) ioctx;
2233
0
  ret->writecallback = iowrite;
2234
0
  ret->closecallback = ioclose;
2235
0
    }
2236
2237
0
    return(ret);
2238
0
}
2239
#endif /* LIBXML_OUTPUT_ENABLED */
2240
2241
/**
2242
 * Registers a callback for URI input file handling
2243
 *
2244
 * @deprecated Use #xmlCtxtSetResourceLoader or similar functions.
2245
 *
2246
 * @param func  function pointer to the new ParserInputBufferCreateFilenameFunc
2247
 * @returns the old value of the registration function
2248
 */
2249
xmlParserInputBufferCreateFilenameFunc
2250
xmlParserInputBufferCreateFilenameDefault(
2251
        xmlParserInputBufferCreateFilenameFunc func)
2252
0
{
2253
0
    xmlParserInputBufferCreateFilenameFunc old;
2254
2255
0
    old = xmlParserInputBufferCreateFilenameValue;
2256
0
    if (old == NULL)
2257
0
        old = __xmlParserInputBufferCreateFilename;
2258
2259
0
    if (func == __xmlParserInputBufferCreateFilename)
2260
0
        func = NULL;
2261
0
    xmlParserInputBufferCreateFilenameValue = func;
2262
0
    return(old);
2263
0
}
2264
2265
/**
2266
 * Registers a callback for URI output file handling
2267
 *
2268
 * @param func  function pointer to the new OutputBufferCreateFilenameFunc
2269
 * @returns the old value of the registration function
2270
 */
2271
xmlOutputBufferCreateFilenameFunc
2272
xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2273
0
{
2274
0
    xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2275
0
#ifdef LIBXML_OUTPUT_ENABLED
2276
0
    if (old == NULL) {
2277
0
    old = __xmlOutputBufferCreateFilename;
2278
0
  }
2279
0
#endif
2280
0
    xmlOutputBufferCreateFilenameValue = func;
2281
0
    return(old);
2282
0
}
2283
2284
/**
2285
 * Push the content of the arry in the input buffer
2286
 * This routine handle the I18N transcoding to internal UTF-8
2287
 * This is used when operating the parser in progressive (push) mode.
2288
 *
2289
 * @deprecated Internal function, don't use.
2290
 *
2291
 * @param in  a buffered parser input
2292
 * @param len  the size in bytes of the array.
2293
 * @param buf  an char array
2294
 * @returns the number of chars read and stored in the buffer, or -1
2295
 *         in case of error.
2296
 */
2297
int
2298
xmlParserInputBufferPush(xmlParserInputBuffer *in,
2299
294k
                   int len, const char *buf) {
2300
294k
    size_t nbchars = 0;
2301
294k
    int ret;
2302
2303
294k
    if (len < 0) return(0);
2304
294k
    if ((in == NULL) || (in->error)) return(-1);
2305
294k
    if (in->encoder != NULL) {
2306
        /*
2307
   * Store the data in the incoming raw buffer
2308
   */
2309
91.0k
        if (in->raw == NULL) {
2310
0
      in->raw = xmlBufCreate(50);
2311
0
            if (in->raw == NULL) {
2312
0
                in->error = XML_ERR_NO_MEMORY;
2313
0
                return(-1);
2314
0
            }
2315
0
  }
2316
91.0k
  ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
2317
91.0k
  if (ret != 0) {
2318
0
            in->error = XML_ERR_NO_MEMORY;
2319
0
      return(-1);
2320
0
        }
2321
2322
  /*
2323
   * convert as much as possible to the parser reading buffer.
2324
   */
2325
91.0k
        nbchars = SIZE_MAX;
2326
91.0k
  if (xmlCharEncInput(in, &nbchars, /* flush */ 0) !=
2327
91.0k
            XML_ENC_ERR_SUCCESS)
2328
151
            return(-1);
2329
90.8k
        if (nbchars > INT_MAX)
2330
0
            nbchars = INT_MAX;
2331
203k
    } else {
2332
203k
  nbchars = len;
2333
203k
        ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
2334
203k
  if (ret != 0) {
2335
0
            in->error = XML_ERR_NO_MEMORY;
2336
0
      return(-1);
2337
0
        }
2338
203k
    }
2339
294k
    return(nbchars);
2340
294k
}
2341
2342
/*
2343
 * When reading from an Input channel indicated end of file or error
2344
 * don't reread from it again.
2345
 */
2346
static int
2347
endOfInput (void * context ATTRIBUTE_UNUSED,
2348
      char * buffer ATTRIBUTE_UNUSED,
2349
0
      int len ATTRIBUTE_UNUSED) {
2350
0
    return(0);
2351
0
}
2352
2353
/**
2354
 * Grow up the content of the input buffer, the old data are preserved
2355
 * This routine handle the I18N transcoding to internal UTF-8
2356
 * This routine is used when operating the parser in normal (pull) mode
2357
 *
2358
 * @deprecated Internal function, don't use.
2359
 *
2360
 * @param in  a buffered parser input
2361
 * @param len  indicative value of the amount of chars to read
2362
 * @returns the number of chars read and stored in the buffer, or -1
2363
 *         in case of error.
2364
 */
2365
int
2366
0
xmlParserInputBufferGrow(xmlParserInputBuffer *in, int len) {
2367
0
    int res = 0;
2368
2369
0
    if ((in == NULL) || (in->error))
2370
0
        return(-1);
2371
2372
0
    if (len < MINLEN)
2373
0
        len = MINLEN;
2374
2375
    /*
2376
     * Call the read method for this I/O type.
2377
     */
2378
0
    if (in->readcallback != NULL) {
2379
0
        xmlBufPtr buf;
2380
2381
0
        if (in->encoder == NULL) {
2382
0
            buf = in->buffer;
2383
0
        } else {
2384
            /*
2385
             * Some users only set 'encoder' and expect us to create
2386
             * the raw buffer lazily.
2387
             */
2388
0
            if (in->raw == NULL) {
2389
0
                in->raw = xmlBufCreate(XML_IO_BUFFER_SIZE);
2390
0
                if (in->raw == NULL) {
2391
0
                    in->error = XML_ERR_NO_MEMORY;
2392
0
                    return(-1);
2393
0
                }
2394
0
            }
2395
0
            buf = in->raw;
2396
0
        }
2397
2398
0
        if (xmlBufGrow(buf, len) < 0) {
2399
0
            in->error = XML_ERR_NO_MEMORY;
2400
0
            return(-1);
2401
0
        }
2402
2403
0
  res = in->readcallback(in->context, (char *)xmlBufEnd(buf), len);
2404
0
  if (res <= 0)
2405
0
      in->readcallback = endOfInput;
2406
0
        if (res < 0) {
2407
0
            if (res == -1)
2408
0
                in->error = XML_IO_UNKNOWN;
2409
0
            else
2410
0
                in->error = -res;
2411
0
            return(-1);
2412
0
        }
2413
2414
0
        if (xmlBufAddLen(buf, res) < 0) {
2415
0
            in->error = XML_ERR_NO_MEMORY;
2416
0
            return(-1);
2417
0
        }
2418
0
    }
2419
2420
    /*
2421
     * Handle encoding.
2422
     */
2423
0
    if (in->encoder != NULL) {
2424
0
        size_t sizeOut;
2425
2426
        /*
2427
         * Don't convert whole buffer when reading from memory.
2428
         */
2429
0
        if (in->readcallback == NULL)
2430
0
            sizeOut = len;
2431
0
        else
2432
0
            sizeOut = SIZE_MAX;
2433
2434
0
  if (xmlCharEncInput(in, &sizeOut, /* flush */ 0) !=
2435
0
            XML_ENC_ERR_SUCCESS)
2436
0
      return(-1);
2437
0
        res = sizeOut;
2438
0
    }
2439
0
    return(res);
2440
0
}
2441
2442
/**
2443
 * Same as #xmlParserInputBufferGrow.
2444
 *
2445
 * @deprecated Internal function, don't use.
2446
 *
2447
 * @param in  a buffered parser input
2448
 * @param len  indicative value of the amount of chars to read
2449
 * @returns the number of chars read and stored in the buffer, or -1
2450
 *         in case of error.
2451
 */
2452
int
2453
0
xmlParserInputBufferRead(xmlParserInputBuffer *in, int len) {
2454
0
    return(xmlParserInputBufferGrow(in, len));
2455
0
}
2456
2457
#ifdef LIBXML_OUTPUT_ENABLED
2458
/**
2459
 * Write the content of the array in the output I/O buffer
2460
 * This routine handle the I18N transcoding from internal UTF-8
2461
 * The buffer is lossless, i.e. will store in case of partial
2462
 * or delayed writes.
2463
 *
2464
 * @param out  a buffered parser output
2465
 * @param len  the size in bytes of the array.
2466
 * @param data  an char array
2467
 * @returns the number of chars immediately written, or -1
2468
 *         in case of error.
2469
 */
2470
int
2471
0
xmlOutputBufferWrite(xmlOutputBuffer *out, int len, const char *data) {
2472
0
    xmlBufPtr buf = NULL;
2473
0
    size_t written = 0;
2474
0
    int ret;
2475
2476
0
    if ((out == NULL) || (out->error))
2477
0
        return(-1);
2478
0
    if (len < 0)
2479
0
        return(0);
2480
2481
0
    ret = xmlBufAdd(out->buffer, (const xmlChar *) data, len);
2482
0
    if (ret != 0) {
2483
0
        out->error = XML_ERR_NO_MEMORY;
2484
0
        return(-1);
2485
0
    }
2486
2487
    /*
2488
     * first handle encoding stuff.
2489
     */
2490
0
    if (out->encoder != NULL) {
2491
        /*
2492
         * Store the data in the incoming raw buffer
2493
         */
2494
0
        if (out->conv == NULL) {
2495
0
            out->conv = xmlBufCreate(MINLEN);
2496
0
            if (out->conv == NULL) {
2497
0
                out->error = XML_ERR_NO_MEMORY;
2498
0
                return(-1);
2499
0
            }
2500
0
        }
2501
2502
        /*
2503
         * convert as much as possible to the parser reading buffer.
2504
         */
2505
0
        if (xmlBufUse(out->buffer) < 256) {
2506
0
            ret = 0;
2507
0
        } else {
2508
0
            ret = xmlCharEncOutput(out, 0);
2509
0
            if (ret < 0)
2510
0
                return(-1);
2511
0
        }
2512
2513
0
        if (out->writecallback)
2514
0
            buf = out->conv;
2515
0
        else
2516
0
            written = ret;
2517
0
    } else {
2518
0
        if (out->writecallback)
2519
0
            buf = out->buffer;
2520
0
        else
2521
0
            written = len;
2522
0
    }
2523
2524
0
    if ((buf != NULL) && (out->writecallback)) {
2525
        /*
2526
         * second write the stuff to the I/O channel
2527
         */
2528
0
        while (1) {
2529
0
            size_t nbchars = xmlBufUse(buf);
2530
2531
0
            if (nbchars < MINLEN)
2532
0
                break;
2533
2534
0
            ret = out->writecallback(out->context,
2535
0
                       (const char *)xmlBufContent(buf), nbchars);
2536
0
            if (ret < 0) {
2537
0
                out->error = (ret == -1) ? XML_IO_WRITE : -ret;
2538
0
                return(-1);
2539
0
            }
2540
0
            if ((ret == 0) || ((size_t) ret > nbchars)) {
2541
0
                out->error = XML_ERR_INTERNAL_ERROR;
2542
0
                return(-1);
2543
0
            }
2544
2545
0
            xmlBufShrink(buf, ret);
2546
0
            written += ret;
2547
0
            if (out->written > INT_MAX - ret)
2548
0
                out->written = INT_MAX;
2549
0
            else
2550
0
                out->written += ret;
2551
0
        }
2552
0
    }
2553
2554
0
    return(written <= INT_MAX ? written : INT_MAX);
2555
0
}
2556
2557
/**
2558
 * Write the content of the string in the output I/O buffer
2559
 * This routine escapes the characters and then handle the I18N
2560
 * transcoding from internal UTF-8
2561
 * The buffer is lossless, i.e. will store in case of partial
2562
 * or delayed writes.
2563
 *
2564
 * @param out  a buffered parser output
2565
 * @param str  a zero terminated UTF-8 string
2566
 * @param escaping  an optional escaping function (or NULL)
2567
 * @returns the number of chars immediately written, or -1
2568
 *         in case of error.
2569
 */
2570
int
2571
xmlOutputBufferWriteEscape(xmlOutputBuffer *out, const xmlChar *str,
2572
0
                           xmlCharEncodingOutputFunc escaping) {
2573
0
    int ret;
2574
0
    int written = 0;
2575
0
    size_t len;
2576
2577
0
    if ((out == NULL) || (out->error) || (str == NULL))
2578
0
        return(-1);
2579
2580
0
    len = strlen((const char *) str);
2581
0
    if (len >= INT_MAX) {
2582
0
        out->error = XML_ERR_RESOURCE_LIMIT;
2583
0
        return(-1);
2584
0
    }
2585
2586
0
    if (escaping == NULL) {
2587
0
        char *escaped = (char *) xmlEscapeText(str, 0);
2588
2589
0
        if (escaped == NULL) {
2590
0
            out->error = XML_ERR_NO_MEMORY;
2591
0
            return(-1);
2592
0
        }
2593
2594
0
        len = strlen(escaped);
2595
0
        if (len >= INT_MAX) {
2596
0
            out->error = XML_ERR_RESOURCE_LIMIT;
2597
0
            return(-1);
2598
0
        }
2599
2600
0
        ret = xmlOutputBufferWrite(out, len, escaped);
2601
2602
0
        xmlFree(escaped);
2603
0
        return(ret);
2604
0
    }
2605
2606
0
    while (len > 0) {
2607
0
        xmlChar buf[1024];
2608
0
        int c_out;
2609
0
        int c_in;
2610
2611
0
  c_out = 1024;
2612
0
  c_in = len;
2613
2614
0
        ret = escaping(buf, &c_out, str, &c_in);
2615
0
        if (ret < 0) {
2616
0
            out->error = XML_ERR_NO_MEMORY;
2617
0
            return(-1);
2618
0
        }
2619
0
        str += c_in;
2620
0
        len -= c_in;
2621
2622
0
        ret = xmlOutputBufferWrite(out, c_out, (char *) buf);
2623
0
        if (ret < 0)
2624
0
            return(ret);
2625
0
        written += ret;
2626
0
    }
2627
2628
0
    return(written);
2629
0
}
2630
2631
/**
2632
 * Write the content of the string in the output I/O buffer
2633
 * This routine handle the I18N transcoding from internal UTF-8
2634
 * The buffer is lossless, i.e. will store in case of partial
2635
 * or delayed writes.
2636
 *
2637
 * @param out  a buffered parser output
2638
 * @param str  a zero terminated C string
2639
 * @returns the number of chars immediately written, or -1
2640
 *         in case of error.
2641
 */
2642
int
2643
0
xmlOutputBufferWriteString(xmlOutputBuffer *out, const char *str) {
2644
0
    int len;
2645
2646
0
    if ((out == NULL) || (out->error)) return(-1);
2647
0
    if (str == NULL)
2648
0
        return(-1);
2649
0
    len = strlen(str);
2650
2651
0
    if (len > 0)
2652
0
  return(xmlOutputBufferWrite(out, len, str));
2653
0
    return(len);
2654
0
}
2655
2656
/**
2657
 * Write a string surrounded by quotes to an output buffer.
2658
 *
2659
 * Uses double quotes if the string contains no double quotes.
2660
 * Otherwise, uses single quotes if the string contains no
2661
 * single quotes. Otherwise, uses double quotes and escapes
2662
 * double quotes.
2663
 *
2664
 * This should only be used to escape system IDs. Currently,
2665
 * we also use it for public IDs and original entity values.
2666
 *
2667
 * @param buf  output buffer
2668
 * @param string  the string to add
2669
 */
2670
void
2671
xmlOutputBufferWriteQuotedString(xmlOutputBuffer *buf,
2672
0
                                 const xmlChar *string) {
2673
0
    const xmlChar *cur, *base;
2674
2675
0
    if ((buf == NULL) || (buf->error))
2676
0
        return;
2677
2678
0
    if (xmlStrchr(string, '\"')) {
2679
0
        if (xmlStrchr(string, '\'')) {
2680
0
      xmlOutputBufferWrite(buf, 1, "\"");
2681
0
            base = cur = string;
2682
0
            while(*cur != 0){
2683
0
                if(*cur == '"'){
2684
0
                    if (base != cur)
2685
0
                        xmlOutputBufferWrite(buf, cur - base,
2686
0
                                             (const char *) base);
2687
0
                    xmlOutputBufferWrite(buf, 6, "&quot;");
2688
0
                    cur++;
2689
0
                    base = cur;
2690
0
                }
2691
0
                else {
2692
0
                    cur++;
2693
0
                }
2694
0
            }
2695
0
            if (base != cur)
2696
0
                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
2697
0
      xmlOutputBufferWrite(buf, 1, "\"");
2698
0
  }
2699
0
        else{
2700
0
      xmlOutputBufferWrite(buf, 1, "'");
2701
0
            xmlOutputBufferWriteString(buf, (const char *) string);
2702
0
      xmlOutputBufferWrite(buf, 1, "'");
2703
0
        }
2704
0
    } else {
2705
0
        xmlOutputBufferWrite(buf, 1, "\"");
2706
0
        xmlOutputBufferWriteString(buf, (const char *) string);
2707
0
        xmlOutputBufferWrite(buf, 1, "\"");
2708
0
    }
2709
0
}
2710
2711
/**
2712
 * flushes the output I/O channel
2713
 *
2714
 * @param out  a buffered output
2715
 * @returns the number of byte written or -1 in case of error.
2716
 */
2717
int
2718
0
xmlOutputBufferFlush(xmlOutputBuffer *out) {
2719
0
    int nbchars = 0, ret = 0;
2720
2721
0
    if ((out == NULL) || (out->error)) return(-1);
2722
    /*
2723
     * first handle encoding stuff.
2724
     */
2725
0
    if ((out->conv != NULL) && (out->encoder != NULL)) {
2726
  /*
2727
   * convert as much as possible to the parser output buffer.
2728
   */
2729
0
  do {
2730
0
      nbchars = xmlCharEncOutput(out, 0);
2731
0
      if (nbchars < 0)
2732
0
    return(-1);
2733
0
  } while (nbchars);
2734
0
    }
2735
2736
    /*
2737
     * second flush the stuff to the I/O channel
2738
     */
2739
0
    if ((out->conv != NULL) && (out->encoder != NULL) &&
2740
0
  (out->writecallback != NULL)) {
2741
0
  ret = out->writecallback(out->context,
2742
0
                                 (const char *)xmlBufContent(out->conv),
2743
0
                                 xmlBufUse(out->conv));
2744
0
  if (ret >= 0)
2745
0
      xmlBufShrink(out->conv, ret);
2746
0
    } else if (out->writecallback != NULL) {
2747
0
  ret = out->writecallback(out->context,
2748
0
                                 (const char *)xmlBufContent(out->buffer),
2749
0
                                 xmlBufUse(out->buffer));
2750
0
  if (ret >= 0)
2751
0
      xmlBufShrink(out->buffer, ret);
2752
0
    }
2753
0
    if (ret < 0) {
2754
0
        out->error = (ret == -1) ? XML_IO_WRITE : -ret;
2755
0
  return(ret);
2756
0
    }
2757
0
    if (out->written > INT_MAX - ret)
2758
0
        out->written = INT_MAX;
2759
0
    else
2760
0
        out->written += ret;
2761
2762
0
    return(ret);
2763
0
}
2764
#endif /* LIBXML_OUTPUT_ENABLED */
2765
2766
/**
2767
 * lookup the directory for that file
2768
 *
2769
 * @param filename  the path to a file
2770
 * @returns a new allocated string containing the directory, or NULL.
2771
 */
2772
char *
2773
27.4k
xmlParserGetDirectory(const char *filename) {
2774
27.4k
    char *ret = NULL;
2775
27.4k
    char dir[1024];
2776
27.4k
    char *cur;
2777
2778
27.4k
    if (filename == NULL) return(NULL);
2779
2780
#if defined(_WIN32)
2781
#   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
2782
#else
2783
27.4k
#   define IS_XMLPGD_SEP(ch) (ch=='/')
2784
27.4k
#endif
2785
2786
27.4k
    strncpy(dir, filename, 1023);
2787
27.4k
    dir[1023] = 0;
2788
27.4k
    cur = &dir[strlen(dir)];
2789
27.4k
    while (cur > dir) {
2790
0
         if (IS_XMLPGD_SEP(*cur)) break;
2791
0
   cur --;
2792
0
    }
2793
27.4k
    if (IS_XMLPGD_SEP(*cur)) {
2794
0
        if (cur == dir) dir[1] = 0;
2795
0
  else *cur = 0;
2796
0
  ret = xmlMemStrdup(dir);
2797
27.4k
    } else {
2798
27.4k
        ret = xmlMemStrdup(".");
2799
27.4k
    }
2800
27.4k
    return(ret);
2801
27.4k
#undef IS_XMLPGD_SEP
2802
27.4k
}
2803
2804
/**
2805
 * Like #xmlCheckFilename but handles file URIs.
2806
 *
2807
 * @deprecated Internal function, don't use.
2808
 *
2809
 * @param filename  the path to check
2810
 * @returns 0, 1, or 2.
2811
 */
2812
int
2813
0
xmlNoNetExists(const char *filename) {
2814
0
    char *fromUri;
2815
0
    int ret;
2816
2817
0
    if (filename == NULL)
2818
0
  return(0);
2819
2820
0
    if (xmlConvertUriToPath(filename, &fromUri) < 0)
2821
0
        return(0);
2822
2823
0
    if (fromUri != NULL)
2824
0
        filename = fromUri;
2825
2826
0
    ret =  xmlCheckFilename(filename);
2827
2828
0
    xmlFree(fromUri);
2829
0
    return(ret);
2830
0
}
2831
2832
/************************************************************************
2833
 *                  *
2834
 *      Input/output callbacks        *
2835
 *                  *
2836
 ************************************************************************/
2837
2838
/**
2839
 * Initialize callback tables.
2840
 */
2841
void
2842
xmlInitIOCallbacks(void)
2843
4
{
2844
4
    xmlInputCallbackNr = 1;
2845
4
    xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch;
2846
2847
4
#ifdef LIBXML_OUTPUT_ENABLED
2848
4
    xmlOutputCallbackNr = 1;
2849
4
    xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch;
2850
4
#endif
2851
4
}
2852
2853
/**
2854
 * Register a new set of I/O callback for handling parser input.
2855
 *
2856
 * @deprecated Use #xmlCtxtSetResourceLoader or similar functions.
2857
 *
2858
 * @param matchFunc  the xmlInputMatchCallback
2859
 * @param openFunc  the xmlInputOpenCallback
2860
 * @param readFunc  the xmlInputReadCallback
2861
 * @param closeFunc  the xmlInputCloseCallback
2862
 * @returns the registered handler number or -1 in case of error
2863
 */
2864
int
2865
xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2866
  xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2867
0
  xmlInputCloseCallback closeFunc) {
2868
0
    xmlInitParser();
2869
2870
0
    if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2871
0
  return(-1);
2872
0
    }
2873
0
    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2874
0
    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2875
0
    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2876
0
    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
2877
0
    return(xmlInputCallbackNr++);
2878
0
}
2879
2880
/**
2881
 * Registers the default compiled-in I/O handlers.
2882
 */
2883
void
2884
0
xmlRegisterDefaultInputCallbacks(void) {
2885
0
    xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
2886
0
}
2887
2888
/**
2889
 * Clear the top input callback from the input stack. this includes the
2890
 * compiled-in I/O.
2891
 *
2892
 * @returns the number of input callback registered or -1 in case of error.
2893
 */
2894
int
2895
xmlPopInputCallbacks(void)
2896
0
{
2897
0
    xmlInitParser();
2898
2899
0
    if (xmlInputCallbackNr <= 0)
2900
0
        return(-1);
2901
2902
0
    xmlInputCallbackNr--;
2903
2904
0
    return(xmlInputCallbackNr);
2905
0
}
2906
2907
/**
2908
 * clears the entire input callback table. this includes the
2909
 * compiled-in I/O.
2910
 */
2911
void
2912
xmlCleanupInputCallbacks(void)
2913
0
{
2914
0
    xmlInitParser();
2915
2916
0
    xmlInputCallbackNr = 0;
2917
0
}
2918
2919
#ifdef LIBXML_OUTPUT_ENABLED
2920
/**
2921
 * Register a new set of I/O callback for handling output.
2922
 *
2923
 * @param matchFunc  the xmlOutputMatchCallback
2924
 * @param openFunc  the xmlOutputOpenCallback
2925
 * @param writeFunc  the xmlOutputWriteCallback
2926
 * @param closeFunc  the xmlOutputCloseCallback
2927
 * @returns the registered handler number or -1 in case of error
2928
 */
2929
int
2930
xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2931
  xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2932
0
  xmlOutputCloseCallback closeFunc) {
2933
0
    xmlInitParser();
2934
2935
0
    if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
2936
0
  return(-1);
2937
0
    }
2938
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2939
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2940
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2941
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
2942
0
    return(xmlOutputCallbackNr++);
2943
0
}
2944
2945
/**
2946
 * Registers the default compiled-in I/O handlers.
2947
 */
2948
void
2949
0
xmlRegisterDefaultOutputCallbacks (void) {
2950
0
    xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
2951
0
}
2952
2953
/**
2954
 * Remove the top output callbacks from the output stack. This includes the
2955
 * compiled-in I/O.
2956
 *
2957
 * @returns the number of output callback registered or -1 in case of error.
2958
 */
2959
int
2960
xmlPopOutputCallbacks(void)
2961
0
{
2962
0
    xmlInitParser();
2963
2964
0
    if (xmlOutputCallbackNr <= 0)
2965
0
        return(-1);
2966
2967
0
    xmlOutputCallbackNr--;
2968
2969
0
    return(xmlOutputCallbackNr);
2970
0
}
2971
2972
/**
2973
 * clears the entire output callback table. this includes the
2974
 * compiled-in I/O callbacks.
2975
 */
2976
void
2977
xmlCleanupOutputCallbacks(void)
2978
0
{
2979
0
    xmlInitParser();
2980
2981
0
    xmlOutputCallbackNr = 0;
2982
0
}
2983
#endif /* LIBXML_OUTPUT_ENABLED */
2984