Coverage Report

Created: 2025-07-01 06:27

/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
17.6k
#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
1.77k
                 unsigned flags) {
310
1.77k
    const xmlChar *cur;
311
1.77k
    const signed char *tab;
312
313
1.77k
    if (string == NULL)
314
0
        return;
315
316
1.77k
#ifdef LIBXML_HTML_ENABLED
317
1.77k
    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
1.77k
    else
324
1.77k
#endif
325
1.77k
    {
326
1.77k
        if (flags & XML_ESCAPE_QUOT)
327
0
            tab = xmlEscapeTabQuot;
328
1.77k
        else if (flags & XML_ESCAPE_ATTR)
329
0
            tab = xmlEscapeTabAttr;
330
1.77k
        else
331
1.77k
            tab = xmlEscapeTab;
332
1.77k
    }
333
334
1.77k
    cur = string;
335
336
1.77k
    while (1) {
337
1.77k
        const xmlChar *base;
338
1.77k
        int c;
339
1.77k
        int offset;
340
341
1.77k
        base = cur;
342
1.77k
        offset = -1;
343
344
7.09k
        while (1) {
345
7.09k
            if ((size_t) (cur - string) >= maxSize)
346
0
                break;
347
348
7.09k
            c = (unsigned char) *cur;
349
350
7.09k
            if (c < 0x80) {
351
7.09k
                offset = tab[c];
352
7.09k
                if (offset >= 0)
353
1.77k
                    break;
354
7.09k
            } else if (flags & XML_ESCAPE_NON_ASCII) {
355
0
                break;
356
0
            }
357
358
5.31k
            cur += 1;
359
5.31k
        }
360
361
1.77k
        if (cur > base)
362
1.77k
            xmlOutputBufferWrite(buf, cur - base, (char *) base);
363
364
1.77k
        if ((size_t) (cur - string) >= maxSize)
365
0
            break;
366
367
1.77k
        if (offset >= 0) {
368
1.77k
            if (c == 0)
369
1.77k
                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
1.77k
    }
393
1.77k
}
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
12
{
411
12
    xmlParserErrors code;
412
413
12
    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
12
        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
12
    }
563
564
12
    return(code);
565
12
}
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
3.13k
xmlConvertUriToPath(const char *uri, char **out) {
684
3.13k
    const char *escaped;
685
3.13k
    char *unescaped;
686
687
3.13k
    *out = NULL;
688
689
3.13k
    if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file://localhost/", 17)) {
690
0
  escaped = &uri[16];
691
3.13k
    } else if (!xmlStrncasecmp(BAD_CAST uri, BAD_CAST "file:///", 8)) {
692
0
  escaped = &uri[7];
693
3.13k
    } 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
3.13k
    } else {
697
3.13k
        return(1);
698
3.13k
    }
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
3.13k
xmlFdOpen(const char *filename, int write, int *out) {
725
3.13k
    char *fromUri = NULL;
726
3.13k
    int flags;
727
3.13k
    int fd;
728
3.13k
    xmlParserErrors ret;
729
730
3.13k
    *out = -1;
731
3.13k
    if (filename == NULL)
732
0
        return(XML_ERR_ARGUMENT);
733
734
3.13k
    if (xmlConvertUriToPath(filename, &fromUri) < 0)
735
0
        return(XML_ERR_NO_MEMORY);
736
737
3.13k
    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
3.13k
    if (write)
758
0
        flags = O_WRONLY | O_CREAT | O_TRUNC;
759
3.13k
    else
760
3.13k
        flags = O_RDONLY;
761
3.13k
    fd = open(filename, flags, 0666);
762
3.13k
#endif /* WIN32 */
763
764
3.13k
    if (fd < 0) {
765
        /*
766
         * Windows and possibly other platforms return EINVAL
767
         * for invalid filenames.
768
         */
769
3.12k
        if ((errno == ENOENT) || (errno == EINVAL)) {
770
3.12k
            ret = XML_IO_ENOENT;
771
3.12k
        } else {
772
0
            ret = xmlIOErr(errno);
773
0
        }
774
3.12k
    } else {
775
12
        *out = fd;
776
12
        ret = XML_ERR_OK;
777
12
    }
778
779
3.13k
    xmlFree(fromUri);
780
3.13k
    return(ret);
781
3.13k
}
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
12
xmlFdRead(void *context, char *buffer, int len) {
793
12
    xmlFdIOCtxt *fdctxt = context;
794
12
    int fd = fdctxt->fd;
795
12
    int ret = 0;
796
12
    int bytes;
797
798
12
    while (len > 0) {
799
12
        bytes = read(fd, buffer, len);
800
12
        if (bytes < 0) {
801
            /*
802
             * If we already got some bytes, return them without
803
             * raising an error.
804
             */
805
12
            if (ret > 0)
806
0
                break;
807
12
            return(-xmlIOErr(errno));
808
12
        }
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
12
}
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
68
xmlFdWrite(void *context, const char *buffer, int len) {
830
68
    xmlFdIOCtxt *fdctxt = context;
831
68
    int fd = fdctxt->fd;
832
68
    int ret = 0;
833
68
    int bytes;
834
835
102
    while (len > 0) {
836
34
  bytes = write(fd, buffer, len);
837
34
  if (bytes < 0)
838
0
            return(-xmlIOErr(errno));
839
34
        ret += bytes;
840
34
        buffer += bytes;
841
34
        len -= bytes;
842
34
    }
843
844
68
    return(ret);
845
68
}
846
#endif /* LIBXML_OUTPUT_ENABLED */
847
848
static int
849
34
xmlFdFree(void *context) {
850
34
    xmlFree(context);
851
34
    return(XML_ERR_OK);
852
34
}
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
12
xmlFdClose (void * context) {
862
12
    xmlFdIOCtxt *fdctxt = context;
863
12
    int fd = fdctxt->fd;
864
12
    int ret;
865
866
12
    ret = close(fd);
867
868
12
    xmlFree(fdctxt);
869
870
12
    if (ret < 0)
871
0
        return(xmlIOErr(errno));
872
873
12
    return(XML_ERR_OK);
874
12
}
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
815
xmlFileWrite(void *context, const char *buffer, int len) {
1003
815
    FILE *file = context;
1004
815
    size_t bytes;
1005
1006
815
    if ((context == NULL) || (buffer == NULL))
1007
0
        return(-1);
1008
1009
815
    errno = 0;
1010
815
    bytes = fwrite(buffer, 1, len, file);
1011
815
    if (bytes < (size_t) len)
1012
0
        return(-xmlIOErr(errno));
1013
1014
815
    return(len);
1015
815
}
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
815
xmlFileFlush (void * context) {
1025
815
    FILE *file = context;
1026
1027
815
    if (file == NULL)
1028
0
        return(-1);
1029
1030
815
    if (fflush(file) != 0)
1031
0
        return(xmlIOErr(errno));
1032
1033
815
    return(XML_ERR_OK);
1034
815
}
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
9
xmlGzfileWrite (void * context, const char * buffer, int len) {
1117
9
    int ret;
1118
1119
9
    ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1120
9
    if (ret < 0)
1121
0
        return(-XML_IO_UNKNOWN);
1122
9
    return(ret);
1123
9
}
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
21
xmlGzfileClose (void * context) {
1133
21
    if (gzclose((gzFile) context) != Z_OK)
1134
0
        return(XML_IO_UNKNOWN);
1135
21
    return(0);
1136
21
}
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
12
xmlXzfileClose (void * context) {
1174
12
    if (__libxml2_xzclose((xzFile) context) != LZMA_OK)
1175
0
        return(XML_IO_UNKNOWN);
1176
12
    return(0);
1177
12
}
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
/**
1192
 * Update the buffer to read from `fd`. Supports the XML_INPUT_UNZIP
1193
 * flag.
1194
 *
1195
 * @param buf  parser input buffer
1196
 * @param fd  file descriptor
1197
 * @param flags  flags
1198
 * @returns an xmlParserErrors code.
1199
 */
1200
xmlParserErrors
1201
xmlInputFromFd(xmlParserInputBuffer *buf, int fd,
1202
12
               xmlParserInputFlags flags) {
1203
12
    xmlFdIOCtxt *fdctxt;
1204
12
    int copy;
1205
1206
12
    (void) flags;
1207
1208
12
#ifdef LIBXML_LZMA_ENABLED
1209
12
    if (flags & XML_INPUT_UNZIP) {
1210
12
        xzFile xzStream;
1211
12
        off_t pos;
1212
1213
12
        pos = lseek(fd, 0, SEEK_CUR);
1214
1215
12
        copy = dup(fd);
1216
12
        if (copy == -1)
1217
0
            return(xmlIOErr(errno));
1218
1219
12
        xzStream = __libxml2_xzdopen("?", copy, "rb");
1220
1221
12
        if (xzStream == NULL) {
1222
0
            close(copy);
1223
12
        } else {
1224
12
            int compressed = (__libxml2_xzcompressed(xzStream) > 0);
1225
1226
12
            if ((compressed) ||
1227
                /* Try to rewind if not gzip compressed */
1228
12
                (pos < 0) ||
1229
12
                (lseek(fd, pos, SEEK_SET) < 0)) {
1230
                /*
1231
                 * If a file isn't seekable, we pipe uncompressed
1232
                 * input through xzlib.
1233
                 */
1234
0
                buf->context = xzStream;
1235
0
                buf->readcallback = xmlXzfileRead;
1236
0
                buf->closecallback = xmlXzfileClose;
1237
0
                buf->compressed = compressed;
1238
1239
0
                return(XML_ERR_OK);
1240
0
            }
1241
1242
12
            xmlXzfileClose(xzStream);
1243
12
        }
1244
12
    }
1245
12
#endif /* LIBXML_LZMA_ENABLED */
1246
1247
12
#ifdef LIBXML_ZLIB_ENABLED
1248
12
    if (flags & XML_INPUT_UNZIP) {
1249
12
        gzFile gzStream;
1250
12
        off_t pos;
1251
1252
12
        pos = lseek(fd, 0, SEEK_CUR);
1253
1254
12
        copy = dup(fd);
1255
12
        if (copy == -1)
1256
0
            return(xmlIOErr(errno));
1257
1258
12
        gzStream = gzdopen(copy, "rb");
1259
1260
12
        if (gzStream == NULL) {
1261
0
            close(copy);
1262
12
        } else {
1263
12
            int compressed = (gzdirect(gzStream) == 0);
1264
1265
12
            if ((compressed) ||
1266
                /* Try to rewind if not gzip compressed */
1267
12
                (pos < 0) ||
1268
12
                (lseek(fd, pos, SEEK_SET) < 0)) {
1269
                /*
1270
                 * If a file isn't seekable, we pipe uncompressed
1271
                 * input through zlib.
1272
                 */
1273
0
                buf->context = gzStream;
1274
0
                buf->readcallback = xmlGzfileRead;
1275
0
                buf->closecallback = xmlGzfileClose;
1276
0
                buf->compressed = compressed;
1277
1278
0
                return(XML_ERR_OK);
1279
0
            }
1280
1281
12
            xmlGzfileClose(gzStream);
1282
12
        }
1283
12
    }
1284
12
#endif /* LIBXML_ZLIB_ENABLED */
1285
1286
12
    copy = dup(fd);
1287
12
    if (copy == -1)
1288
0
        return(xmlIOErr(errno));
1289
1290
12
    fdctxt = xmlMalloc(sizeof(*fdctxt));
1291
12
    if (fdctxt == NULL) {
1292
0
        close(copy);
1293
0
        return(XML_ERR_NO_MEMORY);
1294
0
    }
1295
12
    fdctxt->fd = copy;
1296
1297
12
    buf->context = fdctxt;
1298
12
    buf->readcallback = xmlFdRead;
1299
12
    buf->closecallback = xmlFdClose;
1300
1301
12
    return(XML_ERR_OK);
1302
12
}
1303
1304
#ifdef LIBXML_OUTPUT_ENABLED
1305
/**
1306
 * @param buf  input buffer to be filled
1307
 * @param filename  filename or URI
1308
 * @param compression  compression level or 0
1309
 * @returns an xmlParserErrors code.
1310
 */
1311
static xmlParserErrors
1312
xmlOutputDefaultOpen(xmlOutputBufferPtr buf, const char *filename,
1313
9
                     int compression) {
1314
9
    xmlFdIOCtxt *fdctxt;
1315
9
    int fd;
1316
1317
9
    (void) compression;
1318
1319
9
    if (!strcmp(filename, "-")) {
1320
9
        fd = dup(STDOUT_FILENO);
1321
1322
9
        if (fd < 0)
1323
0
            return(xmlIOErr(errno));
1324
9
    } else {
1325
0
        int ret;
1326
1327
0
        ret = xmlFdOpen(filename, /* write */ 1, &fd);
1328
0
        if (ret != XML_ERR_OK)
1329
0
            return(ret);
1330
0
    }
1331
1332
9
#ifdef LIBXML_ZLIB_ENABLED
1333
9
    if ((compression > 0) && (compression <= 9)) {
1334
9
        gzFile gzStream;
1335
9
        char mode[15];
1336
1337
9
        snprintf(mode, sizeof(mode), "wb%d", compression);
1338
9
        gzStream = gzdopen(fd, mode);
1339
1340
9
        if (gzStream == NULL) {
1341
0
            close(fd);
1342
0
            return(XML_IO_UNKNOWN);
1343
0
        }
1344
1345
9
        buf->context = gzStream;
1346
9
        buf->writecallback = xmlGzfileWrite;
1347
9
        buf->closecallback = xmlGzfileClose;
1348
1349
9
        return(XML_ERR_OK);
1350
9
    }
1351
0
#endif /* LIBXML_ZLIB_ENABLED */
1352
1353
0
    fdctxt = xmlMalloc(sizeof(*fdctxt));
1354
0
    if (fdctxt == NULL) {
1355
0
        close(fd);
1356
0
        return(XML_ERR_NO_MEMORY);
1357
0
    }
1358
0
    fdctxt->fd = fd;
1359
1360
0
    buf->context = fdctxt;
1361
0
    buf->writecallback = xmlFdWrite;
1362
0
    buf->closecallback = xmlFdClose;
1363
0
    return(XML_ERR_OK);
1364
0
}
1365
#endif
1366
1367
/**
1368
 * Create a buffered parser input for progressive parsing.
1369
 *
1370
 * @deprecated Use xmlNewInputFrom*.
1371
 *
1372
 * The encoding argument is deprecated and should be set to
1373
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1374
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
1375
 *
1376
 * @param enc  the charset encoding if known (deprecated)
1377
 * @returns the new parser input or NULL
1378
 */
1379
xmlParserInputBuffer *
1380
3.23k
xmlAllocParserInputBuffer(xmlCharEncoding enc) {
1381
3.23k
    xmlParserInputBufferPtr ret;
1382
1383
3.23k
    ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1384
3.23k
    if (ret == NULL) {
1385
76
  return(NULL);
1386
76
    }
1387
3.16k
    memset(ret, 0, sizeof(xmlParserInputBuffer));
1388
3.16k
    ret->buffer = xmlBufCreate(XML_IO_BUFFER_SIZE);
1389
3.16k
    if (ret->buffer == NULL) {
1390
0
        xmlFree(ret);
1391
0
  return(NULL);
1392
0
    }
1393
3.16k
    if (enc != XML_CHAR_ENCODING_NONE) {
1394
0
        if (xmlLookupCharEncodingHandler(enc, &ret->encoder) != XML_ERR_OK) {
1395
            /* We can't handle errors properly here. */
1396
0
            xmlFreeParserInputBuffer(ret);
1397
0
            return(NULL);
1398
0
        }
1399
0
    }
1400
3.16k
    if (ret->encoder != NULL)
1401
0
        ret->raw = xmlBufCreate(XML_IO_BUFFER_SIZE);
1402
3.16k
    else
1403
3.16k
        ret->raw = NULL;
1404
3.16k
    ret->readcallback = NULL;
1405
3.16k
    ret->closecallback = NULL;
1406
3.16k
    ret->context = NULL;
1407
3.16k
    ret->compressed = -1;
1408
3.16k
    ret->rawconsumed = 0;
1409
1410
3.16k
    return(ret);
1411
3.16k
}
1412
1413
#ifdef LIBXML_OUTPUT_ENABLED
1414
/**
1415
 * Create a buffered parser output
1416
 *
1417
 * Consumes `encoder` but not in error case.
1418
 *
1419
 * @param encoder  the encoding converter or NULL
1420
 * @returns the new parser output or NULL
1421
 */
1422
xmlOutputBuffer *
1423
942
xmlAllocOutputBuffer(xmlCharEncodingHandler *encoder) {
1424
942
    xmlOutputBufferPtr ret;
1425
1426
942
    ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
1427
942
    if (ret == NULL) {
1428
0
  return(NULL);
1429
0
    }
1430
942
    memset(ret, 0, sizeof(xmlOutputBuffer));
1431
942
    ret->buffer = xmlBufCreate(MINLEN);
1432
942
    if (ret->buffer == NULL) {
1433
0
        xmlFree(ret);
1434
0
  return(NULL);
1435
0
    }
1436
1437
942
    ret->encoder = encoder;
1438
942
    if (encoder != NULL) {
1439
0
        ret->conv = xmlBufCreate(MINLEN);
1440
0
  if (ret->conv == NULL) {
1441
0
            xmlBufFree(ret->buffer);
1442
0
            xmlFree(ret);
1443
0
      return(NULL);
1444
0
  }
1445
1446
  /*
1447
   * This call is designed to initiate the encoder state
1448
   */
1449
0
  xmlCharEncOutput(ret, 1);
1450
0
    } else
1451
942
        ret->conv = NULL;
1452
942
    ret->writecallback = NULL;
1453
942
    ret->closecallback = NULL;
1454
942
    ret->context = NULL;
1455
942
    ret->written = 0;
1456
1457
942
    return(ret);
1458
942
}
1459
#endif /* LIBXML_OUTPUT_ENABLED */
1460
1461
/**
1462
 * Free up the memory used by a buffered parser input
1463
 *
1464
 * @param in  a buffered parser input
1465
 */
1466
void
1467
10.6k
xmlFreeParserInputBuffer(xmlParserInputBuffer *in) {
1468
10.6k
    if (in == NULL) return;
1469
1470
10.6k
    if (in->raw) {
1471
0
        xmlBufFree(in->raw);
1472
0
  in->raw = NULL;
1473
0
    }
1474
10.6k
    if (in->encoder != NULL) {
1475
0
        xmlCharEncCloseFunc(in->encoder);
1476
0
    }
1477
10.6k
    if (in->closecallback != NULL) {
1478
12
  in->closecallback(in->context);
1479
12
    }
1480
10.6k
    if (in->buffer != NULL) {
1481
10.6k
        xmlBufFree(in->buffer);
1482
10.6k
  in->buffer = NULL;
1483
10.6k
    }
1484
1485
10.6k
    xmlFree(in);
1486
10.6k
}
1487
1488
#ifdef LIBXML_OUTPUT_ENABLED
1489
/**
1490
 * flushes and close the output I/O channel
1491
 * and free up all the associated resources
1492
 *
1493
 * @param out  a buffered output
1494
 * @returns the number of byte written or a negative xmlParserErrors
1495
 * code in case of error.
1496
 */
1497
int
1498
xmlOutputBufferClose(xmlOutputBuffer *out)
1499
942
{
1500
942
    int ret;
1501
1502
942
    if (out == NULL)
1503
0
        return (-1);
1504
1505
942
    if (out->writecallback != NULL)
1506
858
        xmlOutputBufferFlush(out);
1507
1508
942
    if (out->closecallback != NULL) {
1509
858
        int code = out->closecallback(out->context);
1510
1511
858
        if ((code != XML_ERR_OK) &&
1512
858
            (!xmlIsCatastrophicError(XML_ERR_FATAL, out->error))) {
1513
0
            if (code < 0)
1514
0
                out->error = XML_IO_UNKNOWN;
1515
0
            else
1516
0
                out->error = code;
1517
0
        }
1518
858
    }
1519
1520
942
    if (out->error != XML_ERR_OK)
1521
0
        ret = -out->error;
1522
942
    else
1523
942
        ret = out->written;
1524
1525
942
    if (out->conv) {
1526
0
        xmlBufFree(out->conv);
1527
0
        out->conv = NULL;
1528
0
    }
1529
942
    if (out->encoder != NULL) {
1530
0
        xmlCharEncCloseFunc(out->encoder);
1531
0
    }
1532
942
    if (out->buffer != NULL) {
1533
942
        xmlBufFree(out->buffer);
1534
942
        out->buffer = NULL;
1535
942
    }
1536
1537
942
    xmlFree(out);
1538
1539
942
    return(ret);
1540
942
}
1541
#endif /* LIBXML_OUTPUT_ENABLED */
1542
1543
/**
1544
 * @param URI  the filename or URI
1545
 * @param enc  encoding enum (deprecated)
1546
 * @param flags  XML_INPUT flags
1547
 * @param out  pointer to resulting input buffer
1548
 * @returns an xmlParserErrors code.
1549
 */
1550
xmlParserErrors
1551
xmlParserInputBufferCreateUrl(const char *URI, xmlCharEncoding enc,
1552
                              xmlParserInputFlags flags,
1553
3.21k
                              xmlParserInputBuffer **out) {
1554
3.21k
    xmlParserInputBufferPtr buf;
1555
3.21k
    xmlParserErrors ret;
1556
3.21k
    int i;
1557
1558
3.21k
    xmlInitParser();
1559
1560
3.21k
    *out = NULL;
1561
3.21k
    if (URI == NULL)
1562
0
        return(XML_ERR_ARGUMENT);
1563
1564
    /*
1565
     * Allocate the Input buffer front-end.
1566
     */
1567
3.21k
    buf = xmlAllocParserInputBuffer(enc);
1568
3.21k
    if (buf == NULL)
1569
76
        return(XML_ERR_NO_MEMORY);
1570
1571
    /*
1572
     * Try to find one of the input accept method accepting that scheme
1573
     * Go in reverse to give precedence to user defined handlers.
1574
     */
1575
3.13k
    ret = XML_IO_ENOENT;
1576
6.25k
    for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
1577
3.13k
        xmlInputCallback *cb = &xmlInputCallbackTable[i];
1578
1579
3.13k
        if (cb->matchcallback == xmlIODefaultMatch) {
1580
3.13k
            int fd;
1581
1582
3.13k
            ret = xmlFdOpen(URI, 0, &fd);
1583
1584
3.13k
            if (ret == XML_ERR_OK) {
1585
12
                ret = xmlInputFromFd(buf, fd, flags);
1586
12
                close(fd);
1587
12
                break;
1588
3.12k
            } else if (ret != XML_IO_ENOENT) {
1589
0
                break;
1590
0
            }
1591
3.13k
        } else if ((cb->matchcallback != NULL) &&
1592
0
                   (cb->matchcallback(URI) != 0)) {
1593
0
            buf->context = cb->opencallback(URI);
1594
0
            if (buf->context != NULL) {
1595
0
                buf->readcallback = cb->readcallback;
1596
0
                buf->closecallback = cb->closecallback;
1597
0
                ret = XML_ERR_OK;
1598
0
                break;
1599
0
            }
1600
0
        }
1601
3.13k
    }
1602
3.13k
    if (ret != XML_ERR_OK) {
1603
3.12k
        xmlFreeParserInputBuffer(buf);
1604
3.12k
        *out = NULL;
1605
3.12k
  return(ret);
1606
3.12k
    }
1607
1608
12
    *out = buf;
1609
12
    return(ret);
1610
3.13k
}
1611
1612
/**
1613
 * Create a buffered parser input for the progressive parsing of a file
1614
 * Automatic support for ZLIB/Compress compressed document is provided
1615
 * by default if found at compile-time.
1616
 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1617
 *
1618
 * Internal implementation, never uses the callback installed with
1619
 * #xmlParserInputBufferCreateFilenameDefault.
1620
 *
1621
 * @deprecated Use #xmlNewInputFromUrl.
1622
 *
1623
 * @param URI  a C string containing the URI or filename
1624
 * @param enc  the charset encoding if known
1625
 * @returns the new parser input or NULL
1626
 */
1627
xmlParserInputBuffer *
1628
0
__xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1629
0
    xmlParserInputBufferPtr ret;
1630
1631
0
    xmlParserInputBufferCreateUrl(URI, enc, 0, &ret);
1632
0
    return(ret);
1633
0
}
1634
1635
/**
1636
 * Create a buffered parser input for the progressive parsing of a file
1637
 * Automatic support for ZLIB/Compress compressed document is provided
1638
 * by default if found at compile-time.
1639
 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1640
 *
1641
 * Allows the actual function to be overridden with
1642
 * #xmlParserInputBufferCreateFilenameDefault.
1643
 *
1644
 * @deprecated Use #xmlNewInputFromUrl.
1645
 *
1646
 * @param URI  a C string containing the URI or filename
1647
 * @param enc  the charset encoding if known
1648
 * @returns the new parser input or NULL
1649
 */
1650
xmlParserInputBuffer *
1651
0
xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1652
0
    xmlParserInputBufferPtr ret;
1653
0
    xmlParserErrors code;
1654
1655
0
    if (xmlParserInputBufferCreateFilenameValue != NULL)
1656
0
        return(xmlParserInputBufferCreateFilenameValue(URI, enc));
1657
1658
0
    code = xmlParserInputBufferCreateUrl(URI, enc, 0, &ret);
1659
1660
    /*
1661
     * xmlParserInputBufferCreateFilename has no way to return
1662
     * the kind of error although it really is crucial.
1663
     * All we can do is to set the global error.
1664
     */
1665
0
    if ((code != XML_ERR_OK) && (code != XML_IO_ENOENT)) {
1666
0
        if (xmlRaiseError(NULL, NULL, NULL, NULL, NULL, XML_FROM_IO, code,
1667
0
                          XML_ERR_ERROR, URI, 0, NULL, NULL, NULL, 0, 0,
1668
0
                          "Failed to open file\n") < 0)
1669
0
            xmlRaiseMemoryError(NULL, NULL, NULL, XML_FROM_IO, NULL);
1670
0
    }
1671
1672
0
    return(ret);
1673
0
}
1674
1675
#ifdef LIBXML_OUTPUT_ENABLED
1676
/**
1677
 * Create a buffered  output for the progressive saving of a file
1678
 * If filename is `"-"` then we use stdout as the output.
1679
 * Automatic support for ZLIB/Compress compressed document is provided
1680
 * by default if found at compile-time.
1681
 *
1682
 * Consumes `encoder` but not in error case.
1683
 *
1684
 * Internal implementation, never uses the callback installed with
1685
 * #xmlOutputBufferCreateFilenameDefault.
1686
 *
1687
 * @param URI  a C string containing the URI or filename
1688
 * @param encoder  the encoding converter or NULL
1689
 * @param compression  the compression ration (0 none, 9 max).
1690
 * @returns the new output or NULL
1691
 */
1692
xmlOutputBuffer *
1693
__xmlOutputBufferCreateFilename(const char *URI,
1694
                              xmlCharEncodingHandler *encoder,
1695
9
                              int compression) {
1696
9
    xmlOutputBufferPtr ret = NULL;
1697
9
    xmlURIPtr puri;
1698
9
    int i = 0;
1699
9
    char *unescaped = NULL;
1700
1701
9
    xmlInitParser();
1702
1703
9
    if (URI == NULL)
1704
0
        goto error;
1705
1706
9
    puri = xmlParseURI(URI);
1707
9
    if (puri != NULL) {
1708
        /*
1709
         * try to limit the damages of the URI unescaping code.
1710
         */
1711
9
        if (puri->scheme == NULL) {
1712
9
            unescaped = xmlURIUnescapeString(URI, 0, NULL);
1713
9
            if (unescaped == NULL) {
1714
0
                xmlFreeURI(puri);
1715
0
                goto error;
1716
0
            }
1717
9
            URI = unescaped;
1718
9
        }
1719
9
        xmlFreeURI(puri);
1720
9
    }
1721
1722
    /*
1723
     * Allocate the Output buffer front-end.
1724
     */
1725
9
    ret = xmlAllocOutputBuffer(encoder);
1726
9
    if (ret == NULL)
1727
0
        goto error;
1728
1729
    /*
1730
     * Try to find one of the output accept method accepting that scheme
1731
     * Go in reverse to give precedence to user defined handlers.
1732
     */
1733
9
    for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
1734
9
        xmlOutputCallback *cb = &xmlOutputCallbackTable[i];
1735
9
        xmlParserErrors code;
1736
1737
9
        if (cb->matchcallback == xmlIODefaultMatch) {
1738
9
            code = xmlOutputDefaultOpen(ret, URI, compression);
1739
            /* TODO: Handle other errors */
1740
9
            if (code == XML_ERR_OK)
1741
9
                break;
1742
9
        } else if ((cb->matchcallback != NULL) &&
1743
0
                   (cb->matchcallback(URI) != 0)) {
1744
0
            ret->context = cb->opencallback(URI);
1745
0
            if (ret->context != NULL) {
1746
0
                ret->writecallback = cb->writecallback;
1747
0
                ret->closecallback = cb->closecallback;
1748
0
                break;
1749
0
            }
1750
0
        }
1751
9
    }
1752
1753
9
    if (ret->context == NULL) {
1754
        /* Don't free encoder */
1755
0
        ret->encoder = NULL;
1756
0
        xmlOutputBufferClose(ret);
1757
0
  ret = NULL;
1758
0
    }
1759
1760
9
error:
1761
9
    xmlFree(unescaped);
1762
9
    return(ret);
1763
9
}
1764
1765
/**
1766
 * Create a buffered  output for the progressive saving of a file
1767
 * If filename is `"-"` then we use stdout as the output.
1768
 * Automatic support for ZLIB/Compress compressed document is provided
1769
 * by default if found at compile-time.
1770
 *
1771
 * Consumes `encoder` but not in error case.
1772
 *
1773
 * Allows the actual function to be overridden with
1774
 * #xmlOutputBufferCreateFilenameDefault.
1775
 *
1776
 * @param URI  a C string containing the URI or filename
1777
 * @param encoder  the encoding converter or NULL
1778
 * @param compression  the compression ration (0 none, 9 max).
1779
 * @returns the new output or NULL
1780
 */
1781
xmlOutputBuffer *
1782
xmlOutputBufferCreateFilename(const char *URI,
1783
                              xmlCharEncodingHandler *encoder,
1784
9
                              int compression ATTRIBUTE_UNUSED) {
1785
9
    if ((xmlOutputBufferCreateFilenameValue)) {
1786
0
    return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
1787
0
  }
1788
9
  return __xmlOutputBufferCreateFilename(URI, encoder, compression);
1789
9
}
1790
#endif /* LIBXML_OUTPUT_ENABLED */
1791
1792
/**
1793
 * Create a buffered parser input for the progressive parsing of a FILE *
1794
 * buffered C I/O
1795
 *
1796
 * @deprecated Don't use.
1797
 *
1798
 * The encoding argument is deprecated and should be set to
1799
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1800
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
1801
 *
1802
 * @param file  a FILE*
1803
 * @param enc  the charset encoding if known (deprecated)
1804
 * @returns the new parser input or NULL
1805
 */
1806
xmlParserInputBuffer *
1807
0
xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
1808
0
    xmlParserInputBufferPtr ret;
1809
1810
0
    if (file == NULL) return(NULL);
1811
1812
0
    ret = xmlAllocParserInputBuffer(enc);
1813
0
    if (ret != NULL) {
1814
0
        ret->context = file;
1815
0
  ret->readcallback = xmlFileRead;
1816
0
  ret->closecallback = NULL;
1817
0
    }
1818
1819
0
    return(ret);
1820
0
}
1821
1822
#ifdef LIBXML_OUTPUT_ENABLED
1823
/**
1824
 * Create a buffered output for the progressive saving to a `FILE *`
1825
 * buffered C I/O.
1826
 *
1827
 * Consumes `encoder` but not in error case.
1828
 *
1829
 * @param file  a `FILE *`
1830
 * @param encoder  the encoding converter or NULL
1831
 * @returns the new parser output or NULL
1832
 */
1833
xmlOutputBuffer *
1834
815
xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandler *encoder) {
1835
815
    xmlOutputBufferPtr ret;
1836
1837
815
    if (file == NULL) {
1838
0
        return(NULL);
1839
0
    }
1840
1841
815
    ret = xmlAllocOutputBuffer(encoder);
1842
815
    if (ret != NULL) {
1843
815
        ret->context = file;
1844
815
  ret->writecallback = xmlFileWrite;
1845
815
  ret->closecallback = xmlFileFlush;
1846
815
    }
1847
1848
815
    return(ret);
1849
815
}
1850
1851
/**
1852
 * Create a buffered output for the progressive saving to a xmlBuffer
1853
 *
1854
 * Consumes `encoder` but not in error case.
1855
 *
1856
 * @param buffer  a xmlBuffer
1857
 * @param encoder  the encoding converter or NULL
1858
 * @returns the new parser output or NULL
1859
 */
1860
xmlOutputBuffer *
1861
xmlOutputBufferCreateBuffer(xmlBuffer *buffer,
1862
0
                            xmlCharEncodingHandler *encoder) {
1863
0
    xmlOutputBufferPtr ret;
1864
1865
0
    if (buffer == NULL) {
1866
0
        return(NULL);
1867
0
    }
1868
1869
0
    ret = xmlOutputBufferCreateIO(xmlBufferWrite, NULL, (void *) buffer,
1870
0
                                  encoder);
1871
1872
0
    return(ret);
1873
0
}
1874
1875
/**
1876
 * Gives a pointer to the data currently held in the output buffer
1877
 *
1878
 * @param out  an xmlOutputBuffer
1879
 * @returns a pointer to the data or NULL in case of error
1880
 */
1881
const xmlChar *
1882
0
xmlOutputBufferGetContent(xmlOutputBuffer *out) {
1883
0
    if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
1884
0
        return(NULL);
1885
1886
0
    return(xmlBufContent(out->buffer));
1887
0
}
1888
1889
/**
1890
 * Gives the length of the data currently held in the output buffer
1891
 *
1892
 * @param out  an xmlOutputBuffer
1893
 * @returns 0 in case or error or no data is held, the size otherwise
1894
 */
1895
size_t
1896
0
xmlOutputBufferGetSize(xmlOutputBuffer *out) {
1897
0
    if ((out == NULL) || (out->buffer == NULL) || (out->error != 0))
1898
0
        return(0);
1899
1900
0
    return(xmlBufUse(out->buffer));
1901
0
}
1902
1903
1904
#endif /* LIBXML_OUTPUT_ENABLED */
1905
1906
/**
1907
 * Create a buffered parser input for the progressive parsing for the input
1908
 * from a file descriptor
1909
 *
1910
 * @deprecated Use #xmlNewInputFromFd.
1911
 *
1912
 * The encoding argument is deprecated and should be set to
1913
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
1914
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
1915
 *
1916
 * @param fd  a file descriptor number
1917
 * @param enc  the charset encoding if known (deprecated)
1918
 * @returns the new parser input or NULL
1919
 */
1920
xmlParserInputBuffer *
1921
0
xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
1922
0
    xmlParserInputBufferPtr ret;
1923
1924
0
    if (fd < 0) return(NULL);
1925
1926
0
    ret = xmlAllocParserInputBuffer(enc);
1927
0
    if (ret != NULL) {
1928
0
        xmlFdIOCtxt *fdctxt;
1929
1930
0
        fdctxt = xmlMalloc(sizeof(*fdctxt));
1931
0
        if (fdctxt == NULL) {
1932
0
            return(NULL);
1933
0
        }
1934
0
        fdctxt->fd = fd;
1935
1936
0
        ret->context = fdctxt;
1937
0
  ret->readcallback = xmlFdRead;
1938
0
        ret->closecallback = xmlFdFree;
1939
0
    }
1940
1941
0
    return(ret);
1942
0
}
1943
1944
typedef struct {
1945
    const char *cur;
1946
    size_t size;
1947
} xmlMemIOCtxt;
1948
1949
static int
1950
0
xmlMemRead(void *vctxt, char *buf, int size) {
1951
0
    xmlMemIOCtxt *ctxt = vctxt;
1952
1953
0
    if ((size_t) size > ctxt->size)
1954
0
        size = ctxt->size;
1955
1956
0
    memcpy(buf, ctxt->cur, size);
1957
0
    ctxt->cur += size;
1958
0
    ctxt->size -= size;
1959
1960
0
    return size;
1961
0
}
1962
1963
static int
1964
0
xmlMemClose(void *vctxt) {
1965
0
    xmlMemIOCtxt *ctxt = vctxt;
1966
1967
0
    xmlFree(ctxt);
1968
0
    return(0);
1969
0
}
1970
1971
/**
1972
 * Create an input buffer for memory.
1973
 *
1974
 * @param mem  memory buffer
1975
 * @param size  size of buffer
1976
 * @param flags  flags
1977
 * @param enc  the charset encoding if known (deprecated)
1978
 * @returns the new input buffer or NULL.
1979
 */
1980
xmlParserInputBuffer *
1981
xmlNewInputBufferMemory(const void *mem, size_t size,
1982
7.48k
                        xmlParserInputFlags flags, xmlCharEncoding enc) {
1983
7.48k
    xmlParserInputBufferPtr ret;
1984
1985
7.48k
    if ((flags & XML_INPUT_BUF_STATIC) &&
1986
7.48k
        ((flags & XML_INPUT_BUF_ZERO_TERMINATED) == 0)) {
1987
0
        xmlMemIOCtxt *ctxt;
1988
1989
        /*
1990
         * Static buffer without zero terminator.
1991
         * Stream memory to avoid a copy.
1992
         */
1993
0
        ret = xmlAllocParserInputBuffer(enc);
1994
0
        if (ret == NULL)
1995
0
            return(NULL);
1996
1997
0
        ctxt = xmlMalloc(sizeof(*ctxt));
1998
0
        if (ctxt == NULL) {
1999
0
            xmlFreeParserInputBuffer(ret);
2000
0
            return(NULL);
2001
0
        }
2002
2003
0
        ctxt->cur = mem;
2004
0
        ctxt->size = size;
2005
2006
0
        ret->context = ctxt;
2007
0
        ret->readcallback = xmlMemRead;
2008
0
        ret->closecallback = xmlMemClose;
2009
7.48k
    } else {
2010
7.48k
        ret = xmlMalloc(sizeof(*ret));
2011
7.48k
        if (ret == NULL)
2012
0
            return(NULL);
2013
7.48k
        memset(ret, 0, sizeof(xmlParserInputBuffer));
2014
7.48k
        ret->compressed = -1;
2015
2016
7.48k
        ret->buffer = xmlBufCreateMem((const xmlChar *) mem, size,
2017
7.48k
                                      (flags & XML_INPUT_BUF_STATIC ? 1 : 0));
2018
7.48k
        if (ret->buffer == NULL) {
2019
0
            xmlFree(ret);
2020
0
            return(NULL);
2021
0
        }
2022
7.48k
    }
2023
2024
7.48k
    return(ret);
2025
7.48k
}
2026
2027
/**
2028
 * Create a parser input buffer for parsing from a memory area.
2029
 *
2030
 * @deprecated Use #xmlNewInputFromMemory.
2031
 *
2032
 * This function makes a copy of the whole input buffer. If you are sure
2033
 * that the contents of the buffer will remain valid until the document
2034
 * was parsed, you can avoid the copy by using
2035
 * #xmlParserInputBufferCreateStatic.
2036
 *
2037
 * The encoding argument is deprecated and should be set to
2038
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
2039
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
2040
 *
2041
 * @param mem  the memory input
2042
 * @param size  the length of the memory block
2043
 * @param enc  the charset encoding if known (deprecated)
2044
 * @returns the new parser input or NULL in case of error.
2045
 */
2046
xmlParserInputBuffer *
2047
0
xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
2048
0
    if ((mem == NULL) || (size < 0))
2049
0
        return(NULL);
2050
2051
0
    return(xmlNewInputBufferMemory(mem, size, 0, enc));
2052
0
}
2053
2054
/**
2055
 * Create a parser input buffer for parsing from a memory area.
2056
 *
2057
 * @deprecated Use #xmlNewInputFromMemory.
2058
 *
2059
 * This functions assumes that the contents of the input buffer remain
2060
 * valid until the document was parsed. Use #xmlParserInputBufferCreateMem
2061
 * otherwise.
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
2070
 * @returns the new parser input or NULL in case of error.
2071
 */
2072
xmlParserInputBuffer *
2073
xmlParserInputBufferCreateStatic(const char *mem, int size,
2074
0
                                 xmlCharEncoding enc) {
2075
0
    if ((mem == NULL) || (size < 0))
2076
0
        return(NULL);
2077
2078
0
    return(xmlNewInputBufferMemory(mem, size, XML_INPUT_BUF_STATIC, enc));
2079
0
}
2080
2081
/**
2082
 * Create an input buffer for a null-terminated C string.
2083
 *
2084
 * @deprecated Use #xmlNewInputFromString.
2085
 *
2086
 * @param str  C string
2087
 * @param flags  flags
2088
 * @returns the new input buffer or NULL.
2089
 */
2090
xmlParserInputBuffer *
2091
0
xmlNewInputBufferString(const char *str, xmlParserInputFlags flags) {
2092
0
    xmlParserInputBufferPtr ret;
2093
2094
0
    ret = xmlMalloc(sizeof(*ret));
2095
0
    if (ret == NULL)
2096
0
  return(NULL);
2097
0
    memset(ret, 0, sizeof(xmlParserInputBuffer));
2098
0
    ret->compressed = -1;
2099
2100
0
    ret->buffer = xmlBufCreateMem((const xmlChar *) str, strlen(str),
2101
0
                                  (flags & XML_INPUT_BUF_STATIC ? 1 : 0));
2102
0
    if (ret->buffer == NULL) {
2103
0
        xmlFree(ret);
2104
0
  return(NULL);
2105
0
    }
2106
2107
0
    return(ret);
2108
0
}
2109
2110
#ifdef LIBXML_OUTPUT_ENABLED
2111
/**
2112
 * Create a buffered output for the progressive saving
2113
 * to a file descriptor
2114
 *
2115
 * Consumes `encoder` but not in error case.
2116
 *
2117
 * @param fd  a file descriptor number
2118
 * @param encoder  the encoding converter or NULL
2119
 * @returns the new parser output or NULL
2120
 */
2121
xmlOutputBuffer *
2122
34
xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandler *encoder) {
2123
34
    xmlOutputBufferPtr ret;
2124
2125
34
    if (fd < 0) {
2126
0
        return(NULL);
2127
0
    }
2128
2129
34
    ret = xmlAllocOutputBuffer(encoder);
2130
34
    if (ret != NULL) {
2131
34
        xmlFdIOCtxt *fdctxt;
2132
2133
34
        fdctxt = xmlMalloc(sizeof(*fdctxt));
2134
34
        if (fdctxt == NULL) {
2135
0
            return(NULL);
2136
0
        }
2137
34
        fdctxt->fd = fd;
2138
2139
34
        ret->context = fdctxt;
2140
34
  ret->writecallback = xmlFdWrite;
2141
34
        ret->closecallback = xmlFdFree;
2142
34
    }
2143
2144
34
    return(ret);
2145
34
}
2146
#endif /* LIBXML_OUTPUT_ENABLED */
2147
2148
/**
2149
 * Create a buffered parser input for the progressive parsing for the input
2150
 * from an I/O handler
2151
 *
2152
 * @deprecated Use #xmlNewInputFromIO.
2153
 *
2154
 * The encoding argument is deprecated and should be set to
2155
 * XML_CHAR_ENCODING_NONE. The encoding can be changed with
2156
 * #xmlSwitchEncoding or #xmlSwitchEncodingName later on.
2157
 *
2158
 * @param ioread  an I/O read function
2159
 * @param ioclose  an I/O close function
2160
 * @param ioctx  an I/O handler
2161
 * @param enc  the charset encoding if known (deprecated)
2162
 * @returns the new parser input or NULL
2163
 */
2164
xmlParserInputBuffer *
2165
xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
2166
0
   xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
2167
0
    xmlParserInputBufferPtr ret;
2168
2169
0
    if (ioread == NULL) return(NULL);
2170
2171
0
    ret = xmlAllocParserInputBuffer(enc);
2172
0
    if (ret != NULL) {
2173
0
        ret->context = (void *) ioctx;
2174
0
  ret->readcallback = ioread;
2175
0
  ret->closecallback = ioclose;
2176
0
    }
2177
2178
0
    return(ret);
2179
0
}
2180
2181
#ifdef LIBXML_OUTPUT_ENABLED
2182
/**
2183
 * Create a buffered output for the progressive saving
2184
 * to an I/O handler
2185
 *
2186
 * Consumes `encoder` but not in error case.
2187
 *
2188
 * @param iowrite  an I/O write function
2189
 * @param ioclose  an I/O close function
2190
 * @param ioctx  an I/O handler
2191
 * @param encoder  the charset encoding if known
2192
 * @returns the new parser output or NULL
2193
 */
2194
xmlOutputBuffer *
2195
xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite,
2196
   xmlOutputCloseCallback  ioclose, void *ioctx,
2197
0
   xmlCharEncodingHandler *encoder) {
2198
0
    xmlOutputBufferPtr ret;
2199
2200
0
    if (iowrite == NULL) {
2201
0
        return(NULL);
2202
0
    }
2203
2204
0
    ret = xmlAllocOutputBuffer(encoder);
2205
0
    if (ret != NULL) {
2206
0
        ret->context = (void *) ioctx;
2207
0
  ret->writecallback = iowrite;
2208
0
  ret->closecallback = ioclose;
2209
0
    }
2210
2211
0
    return(ret);
2212
0
}
2213
#endif /* LIBXML_OUTPUT_ENABLED */
2214
2215
/**
2216
 * Registers a callback for URI input file handling
2217
 *
2218
 * @deprecated Use #xmlCtxtSetResourceLoader or similar functions.
2219
 *
2220
 * @param func  function pointer to the new ParserInputBufferCreateFilenameFunc
2221
 * @returns the old value of the registration function
2222
 */
2223
xmlParserInputBufferCreateFilenameFunc
2224
xmlParserInputBufferCreateFilenameDefault(
2225
        xmlParserInputBufferCreateFilenameFunc func)
2226
0
{
2227
0
    xmlParserInputBufferCreateFilenameFunc old;
2228
2229
0
    old = xmlParserInputBufferCreateFilenameValue;
2230
0
    if (old == NULL)
2231
0
        old = __xmlParserInputBufferCreateFilename;
2232
2233
0
    if (func == __xmlParserInputBufferCreateFilename)
2234
0
        func = NULL;
2235
0
    xmlParserInputBufferCreateFilenameValue = func;
2236
0
    return(old);
2237
0
}
2238
2239
/**
2240
 * Registers a callback for URI output file handling
2241
 *
2242
 * @param func  function pointer to the new OutputBufferCreateFilenameFunc
2243
 * @returns the old value of the registration function
2244
 */
2245
xmlOutputBufferCreateFilenameFunc
2246
xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
2247
0
{
2248
0
    xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
2249
0
#ifdef LIBXML_OUTPUT_ENABLED
2250
0
    if (old == NULL) {
2251
0
    old = __xmlOutputBufferCreateFilename;
2252
0
  }
2253
0
#endif
2254
0
    xmlOutputBufferCreateFilenameValue = func;
2255
0
    return(old);
2256
0
}
2257
2258
/**
2259
 * Push the content of the arry in the input buffer
2260
 * This routine handle the I18N transcoding to internal UTF-8
2261
 * This is used when operating the parser in progressive (push) mode.
2262
 *
2263
 * @deprecated Internal function, don't use.
2264
 *
2265
 * @param in  a buffered parser input
2266
 * @param len  the size in bytes of the array.
2267
 * @param buf  an char array
2268
 * @returns the number of chars read and stored in the buffer, or -1
2269
 *         in case of error.
2270
 */
2271
int
2272
xmlParserInputBufferPush(xmlParserInputBuffer *in,
2273
0
                   int len, const char *buf) {
2274
0
    size_t nbchars = 0;
2275
0
    int ret;
2276
2277
0
    if (len < 0) return(0);
2278
0
    if ((in == NULL) || (in->error)) return(-1);
2279
0
    if (in->encoder != NULL) {
2280
        /*
2281
   * Store the data in the incoming raw buffer
2282
   */
2283
0
        if (in->raw == NULL) {
2284
0
      in->raw = xmlBufCreate(50);
2285
0
            if (in->raw == NULL) {
2286
0
                in->error = XML_ERR_NO_MEMORY;
2287
0
                return(-1);
2288
0
            }
2289
0
  }
2290
0
  ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
2291
0
  if (ret != 0) {
2292
0
            in->error = XML_ERR_NO_MEMORY;
2293
0
      return(-1);
2294
0
        }
2295
2296
  /*
2297
   * convert as much as possible to the parser reading buffer.
2298
   */
2299
0
        nbchars = SIZE_MAX;
2300
0
  if (xmlCharEncInput(in, &nbchars, /* flush */ 0) !=
2301
0
            XML_ENC_ERR_SUCCESS)
2302
0
            return(-1);
2303
0
        if (nbchars > INT_MAX)
2304
0
            nbchars = INT_MAX;
2305
0
    } else {
2306
0
  nbchars = len;
2307
0
        ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
2308
0
  if (ret != 0) {
2309
0
            in->error = XML_ERR_NO_MEMORY;
2310
0
      return(-1);
2311
0
        }
2312
0
    }
2313
0
    return(nbchars);
2314
0
}
2315
2316
/*
2317
 * When reading from an Input channel indicated end of file or error
2318
 * don't reread from it again.
2319
 */
2320
static int
2321
endOfInput (void * context ATTRIBUTE_UNUSED,
2322
      char * buffer ATTRIBUTE_UNUSED,
2323
0
      int len ATTRIBUTE_UNUSED) {
2324
0
    return(0);
2325
0
}
2326
2327
/**
2328
 * Grow up the content of the input buffer, the old data are preserved
2329
 * This routine handle the I18N transcoding to internal UTF-8
2330
 * This routine is used when operating the parser in normal (pull) mode
2331
 *
2332
 * @deprecated Internal function, don't use.
2333
 *
2334
 * @param in  a buffered parser input
2335
 * @param len  indicative value of the amount of chars to read
2336
 * @returns the number of chars read and stored in the buffer, or -1
2337
 *         in case of error.
2338
 */
2339
int
2340
12
xmlParserInputBufferGrow(xmlParserInputBuffer *in, int len) {
2341
12
    int res = 0;
2342
2343
12
    if ((in == NULL) || (in->error))
2344
0
        return(-1);
2345
2346
12
    if (len < MINLEN)
2347
12
        len = MINLEN;
2348
2349
    /*
2350
     * Call the read method for this I/O type.
2351
     */
2352
12
    if (in->readcallback != NULL) {
2353
12
        xmlBufPtr buf;
2354
2355
12
        if (in->encoder == NULL) {
2356
12
            buf = in->buffer;
2357
12
        } else {
2358
            /*
2359
             * Some users only set 'encoder' and expect us to create
2360
             * the raw buffer lazily.
2361
             */
2362
0
            if (in->raw == NULL) {
2363
0
                in->raw = xmlBufCreate(XML_IO_BUFFER_SIZE);
2364
0
                if (in->raw == NULL) {
2365
0
                    in->error = XML_ERR_NO_MEMORY;
2366
0
                    return(-1);
2367
0
                }
2368
0
            }
2369
0
            buf = in->raw;
2370
0
        }
2371
2372
12
        if (xmlBufGrow(buf, len) < 0) {
2373
0
            in->error = XML_ERR_NO_MEMORY;
2374
0
            return(-1);
2375
0
        }
2376
2377
12
  res = in->readcallback(in->context, (char *)xmlBufEnd(buf), len);
2378
12
  if (res <= 0)
2379
12
      in->readcallback = endOfInput;
2380
12
        if (res < 0) {
2381
12
            if (res == -1)
2382
0
                in->error = XML_IO_UNKNOWN;
2383
12
            else
2384
12
                in->error = -res;
2385
12
            return(-1);
2386
12
        }
2387
2388
0
        if (xmlBufAddLen(buf, res) < 0) {
2389
0
            in->error = XML_ERR_NO_MEMORY;
2390
0
            return(-1);
2391
0
        }
2392
0
    }
2393
2394
    /*
2395
     * Handle encoding.
2396
     */
2397
0
    if (in->encoder != NULL) {
2398
0
        size_t sizeOut;
2399
2400
        /*
2401
         * Don't convert whole buffer when reading from memory.
2402
         */
2403
0
        if (in->readcallback == NULL)
2404
0
            sizeOut = len;
2405
0
        else
2406
0
            sizeOut = SIZE_MAX;
2407
2408
0
  if (xmlCharEncInput(in, &sizeOut, /* flush */ 0) !=
2409
0
            XML_ENC_ERR_SUCCESS)
2410
0
      return(-1);
2411
0
        res = sizeOut;
2412
0
    }
2413
0
    return(res);
2414
0
}
2415
2416
/**
2417
 * Same as #xmlParserInputBufferGrow.
2418
 *
2419
 * @deprecated Internal function, don't use.
2420
 *
2421
 * @param in  a buffered parser input
2422
 * @param len  indicative value of the amount of chars to read
2423
 * @returns the number of chars read and stored in the buffer, or -1
2424
 *         in case of error.
2425
 */
2426
int
2427
12
xmlParserInputBufferRead(xmlParserInputBuffer *in, int len) {
2428
12
    return(xmlParserInputBufferGrow(in, len));
2429
12
}
2430
2431
#ifdef LIBXML_OUTPUT_ENABLED
2432
/**
2433
 * Write the content of the array in the output I/O buffer
2434
 * This routine handle the I18N transcoding from internal UTF-8
2435
 * The buffer is lossless, i.e. will store in case of partial
2436
 * or delayed writes.
2437
 *
2438
 * @param out  a buffered parser output
2439
 * @param len  the size in bytes of the array.
2440
 * @param data  an char array
2441
 * @returns the number of chars immediately written, or -1
2442
 *         in case of error.
2443
 */
2444
int
2445
17.2k
xmlOutputBufferWrite(xmlOutputBuffer *out, int len, const char *data) {
2446
17.2k
    xmlBufPtr buf = NULL;
2447
17.2k
    size_t written = 0;
2448
17.2k
    int ret;
2449
2450
17.2k
    if ((out == NULL) || (out->error))
2451
0
        return(-1);
2452
17.2k
    if (len < 0)
2453
0
        return(0);
2454
2455
17.2k
    ret = xmlBufAdd(out->buffer, (const xmlChar *) data, len);
2456
17.2k
    if (ret != 0) {
2457
0
        out->error = XML_ERR_NO_MEMORY;
2458
0
        return(-1);
2459
0
    }
2460
2461
    /*
2462
     * first handle encoding stuff.
2463
     */
2464
17.2k
    if (out->encoder != NULL) {
2465
        /*
2466
         * Store the data in the incoming raw buffer
2467
         */
2468
0
        if (out->conv == NULL) {
2469
0
            out->conv = xmlBufCreate(MINLEN);
2470
0
            if (out->conv == NULL) {
2471
0
                out->error = XML_ERR_NO_MEMORY;
2472
0
                return(-1);
2473
0
            }
2474
0
        }
2475
2476
        /*
2477
         * convert as much as possible to the parser reading buffer.
2478
         */
2479
0
        if (xmlBufUse(out->buffer) < 256) {
2480
0
            ret = 0;
2481
0
        } else {
2482
0
            ret = xmlCharEncOutput(out, 0);
2483
0
            if (ret < 0)
2484
0
                return(-1);
2485
0
        }
2486
2487
0
        if (out->writecallback)
2488
0
            buf = out->conv;
2489
0
        else
2490
0
            written = ret;
2491
17.2k
    } else {
2492
17.2k
        if (out->writecallback)
2493
16.6k
            buf = out->buffer;
2494
588
        else
2495
588
            written = len;
2496
17.2k
    }
2497
2498
17.2k
    if ((buf != NULL) && (out->writecallback)) {
2499
        /*
2500
         * second write the stuff to the I/O channel
2501
         */
2502
16.6k
        while (1) {
2503
16.6k
            size_t nbchars = xmlBufUse(buf);
2504
2505
16.6k
            if (nbchars < MINLEN)
2506
16.6k
                break;
2507
2508
0
            ret = out->writecallback(out->context,
2509
0
                       (const char *)xmlBufContent(buf), nbchars);
2510
0
            if (ret < 0) {
2511
0
                out->error = (ret == -1) ? XML_IO_WRITE : -ret;
2512
0
                return(-1);
2513
0
            }
2514
0
            if ((ret == 0) || ((size_t) ret > nbchars)) {
2515
0
                out->error = XML_ERR_INTERNAL_ERROR;
2516
0
                return(-1);
2517
0
            }
2518
2519
0
            xmlBufShrink(buf, ret);
2520
0
            written += ret;
2521
0
            if (out->written > INT_MAX - ret)
2522
0
                out->written = INT_MAX;
2523
0
            else
2524
0
                out->written += ret;
2525
0
        }
2526
16.6k
    }
2527
2528
17.2k
    return(written <= INT_MAX ? written : INT_MAX);
2529
17.2k
}
2530
2531
/**
2532
 * Write the content of the string in the output I/O buffer
2533
 * This routine escapes the characters and then handle the I18N
2534
 * transcoding from internal UTF-8
2535
 * The buffer is lossless, i.e. will store in case of partial
2536
 * or delayed writes.
2537
 *
2538
 * @param out  a buffered parser output
2539
 * @param str  a zero terminated UTF-8 string
2540
 * @param escaping  an optional escaping function (or NULL)
2541
 * @returns the number of chars immediately written, or -1
2542
 *         in case of error.
2543
 */
2544
int
2545
xmlOutputBufferWriteEscape(xmlOutputBuffer *out, const xmlChar *str,
2546
0
                           xmlCharEncodingOutputFunc escaping) {
2547
0
    int ret;
2548
0
    int written = 0;
2549
0
    size_t len;
2550
2551
0
    if ((out == NULL) || (out->error) || (str == NULL))
2552
0
        return(-1);
2553
2554
0
    len = strlen((const char *) str);
2555
0
    if (len >= INT_MAX) {
2556
0
        out->error = XML_ERR_RESOURCE_LIMIT;
2557
0
        return(-1);
2558
0
    }
2559
2560
0
    if (escaping == NULL) {
2561
0
        char *escaped = (char *) xmlEscapeText(str, 0);
2562
2563
0
        if (escaped == NULL) {
2564
0
            out->error = XML_ERR_NO_MEMORY;
2565
0
            return(-1);
2566
0
        }
2567
2568
0
        len = strlen(escaped);
2569
0
        if (len >= INT_MAX) {
2570
0
            out->error = XML_ERR_RESOURCE_LIMIT;
2571
0
            return(-1);
2572
0
        }
2573
2574
0
        ret = xmlOutputBufferWrite(out, len, escaped);
2575
2576
0
        xmlFree(escaped);
2577
0
        return(ret);
2578
0
    }
2579
2580
0
    while (len > 0) {
2581
0
        xmlChar buf[1024];
2582
0
        int c_out;
2583
0
        int c_in;
2584
2585
0
  c_out = 1024;
2586
0
  c_in = len;
2587
2588
0
        ret = escaping(buf, &c_out, str, &c_in);
2589
0
        if (ret < 0) {
2590
0
            out->error = XML_ERR_NO_MEMORY;
2591
0
            return(-1);
2592
0
        }
2593
0
        str += c_in;
2594
0
        len -= c_in;
2595
2596
0
        ret = xmlOutputBufferWrite(out, c_out, (char *) buf);
2597
0
        if (ret < 0)
2598
0
            return(ret);
2599
0
        written += ret;
2600
0
    }
2601
2602
0
    return(written);
2603
0
}
2604
2605
/**
2606
 * Write the content of the string in the output I/O buffer
2607
 * This routine handle the I18N transcoding from internal UTF-8
2608
 * The buffer is lossless, i.e. will store in case of partial
2609
 * or delayed writes.
2610
 *
2611
 * @param out  a buffered parser output
2612
 * @param str  a zero terminated C string
2613
 * @returns the number of chars immediately written, or -1
2614
 *         in case of error.
2615
 */
2616
int
2617
4.50k
xmlOutputBufferWriteString(xmlOutputBuffer *out, const char *str) {
2618
4.50k
    int len;
2619
2620
4.50k
    if ((out == NULL) || (out->error)) return(-1);
2621
4.50k
    if (str == NULL)
2622
0
        return(-1);
2623
4.50k
    len = strlen(str);
2624
2625
4.50k
    if (len > 0)
2626
4.50k
  return(xmlOutputBufferWrite(out, len, str));
2627
0
    return(len);
2628
4.50k
}
2629
2630
/**
2631
 * Write a string surrounded by quotes to an output buffer.
2632
 *
2633
 * Uses double quotes if the string contains no double quotes.
2634
 * Otherwise, uses single quotes if the string contains no
2635
 * single quotes. Otherwise, uses double quotes and escapes
2636
 * double quotes.
2637
 *
2638
 * This should only be used to escape system IDs. Currently,
2639
 * we also use it for public IDs and original entity values.
2640
 *
2641
 * @param buf  output buffer
2642
 * @param string  the string to add
2643
 */
2644
void
2645
xmlOutputBufferWriteQuotedString(xmlOutputBuffer *buf,
2646
0
                                 const xmlChar *string) {
2647
0
    const xmlChar *cur, *base;
2648
2649
0
    if ((buf == NULL) || (buf->error))
2650
0
        return;
2651
2652
0
    if (xmlStrchr(string, '\"')) {
2653
0
        if (xmlStrchr(string, '\'')) {
2654
0
      xmlOutputBufferWrite(buf, 1, "\"");
2655
0
            base = cur = string;
2656
0
            while(*cur != 0){
2657
0
                if(*cur == '"'){
2658
0
                    if (base != cur)
2659
0
                        xmlOutputBufferWrite(buf, cur - base,
2660
0
                                             (const char *) base);
2661
0
                    xmlOutputBufferWrite(buf, 6, "&quot;");
2662
0
                    cur++;
2663
0
                    base = cur;
2664
0
                }
2665
0
                else {
2666
0
                    cur++;
2667
0
                }
2668
0
            }
2669
0
            if (base != cur)
2670
0
                xmlOutputBufferWrite(buf, cur - base, (const char *) base);
2671
0
      xmlOutputBufferWrite(buf, 1, "\"");
2672
0
  }
2673
0
        else{
2674
0
      xmlOutputBufferWrite(buf, 1, "'");
2675
0
            xmlOutputBufferWriteString(buf, (const char *) string);
2676
0
      xmlOutputBufferWrite(buf, 1, "'");
2677
0
        }
2678
0
    } else {
2679
0
        xmlOutputBufferWrite(buf, 1, "\"");
2680
0
        xmlOutputBufferWriteString(buf, (const char *) string);
2681
0
        xmlOutputBufferWrite(buf, 1, "\"");
2682
0
    }
2683
0
}
2684
2685
/**
2686
 * flushes the output I/O channel
2687
 *
2688
 * @param out  a buffered output
2689
 * @returns the number of byte written or -1 in case of error.
2690
 */
2691
int
2692
976
xmlOutputBufferFlush(xmlOutputBuffer *out) {
2693
976
    int nbchars = 0, ret = 0;
2694
2695
976
    if ((out == NULL) || (out->error)) return(-1);
2696
    /*
2697
     * first handle encoding stuff.
2698
     */
2699
976
    if ((out->conv != NULL) && (out->encoder != NULL)) {
2700
  /*
2701
   * convert as much as possible to the parser output buffer.
2702
   */
2703
0
  do {
2704
0
      nbchars = xmlCharEncOutput(out, 0);
2705
0
      if (nbchars < 0)
2706
0
    return(-1);
2707
0
  } while (nbchars);
2708
0
    }
2709
2710
    /*
2711
     * second flush the stuff to the I/O channel
2712
     */
2713
976
    if ((out->conv != NULL) && (out->encoder != NULL) &&
2714
976
  (out->writecallback != NULL)) {
2715
0
  ret = out->writecallback(out->context,
2716
0
                                 (const char *)xmlBufContent(out->conv),
2717
0
                                 xmlBufUse(out->conv));
2718
0
  if (ret >= 0)
2719
0
      xmlBufShrink(out->conv, ret);
2720
976
    } else if (out->writecallback != NULL) {
2721
892
  ret = out->writecallback(out->context,
2722
892
                                 (const char *)xmlBufContent(out->buffer),
2723
892
                                 xmlBufUse(out->buffer));
2724
892
  if (ret >= 0)
2725
892
      xmlBufShrink(out->buffer, ret);
2726
892
    }
2727
976
    if (ret < 0) {
2728
0
        out->error = (ret == -1) ? XML_IO_WRITE : -ret;
2729
0
  return(ret);
2730
0
    }
2731
976
    if (out->written > INT_MAX - ret)
2732
0
        out->written = INT_MAX;
2733
976
    else
2734
976
        out->written += ret;
2735
2736
976
    return(ret);
2737
976
}
2738
#endif /* LIBXML_OUTPUT_ENABLED */
2739
2740
/**
2741
 * lookup the directory for that file
2742
 *
2743
 * @param filename  the path to a file
2744
 * @returns a new allocated string containing the directory, or NULL.
2745
 */
2746
char *
2747
0
xmlParserGetDirectory(const char *filename) {
2748
0
    char *ret = NULL;
2749
0
    char dir[1024];
2750
0
    char *cur;
2751
2752
0
    if (filename == NULL) return(NULL);
2753
2754
#if defined(_WIN32)
2755
#   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
2756
#else
2757
0
#   define IS_XMLPGD_SEP(ch) (ch=='/')
2758
0
#endif
2759
2760
0
    strncpy(dir, filename, 1023);
2761
0
    dir[1023] = 0;
2762
0
    cur = &dir[strlen(dir)];
2763
0
    while (cur > dir) {
2764
0
         if (IS_XMLPGD_SEP(*cur)) break;
2765
0
   cur --;
2766
0
    }
2767
0
    if (IS_XMLPGD_SEP(*cur)) {
2768
0
        if (cur == dir) dir[1] = 0;
2769
0
  else *cur = 0;
2770
0
  ret = xmlMemStrdup(dir);
2771
0
    } else {
2772
0
        ret = xmlMemStrdup(".");
2773
0
    }
2774
0
    return(ret);
2775
0
#undef IS_XMLPGD_SEP
2776
0
}
2777
2778
/**
2779
 * Like #xmlCheckFilename but handles file URIs.
2780
 *
2781
 * @deprecated Internal function, don't use.
2782
 *
2783
 * @param filename  the path to check
2784
 * @returns 0, 1, or 2.
2785
 */
2786
int
2787
0
xmlNoNetExists(const char *filename) {
2788
0
    char *fromUri;
2789
0
    int ret;
2790
2791
0
    if (filename == NULL)
2792
0
  return(0);
2793
2794
0
    if (xmlConvertUriToPath(filename, &fromUri) < 0)
2795
0
        return(0);
2796
2797
0
    if (fromUri != NULL)
2798
0
        filename = fromUri;
2799
2800
0
    ret =  xmlCheckFilename(filename);
2801
2802
0
    xmlFree(fromUri);
2803
0
    return(ret);
2804
0
}
2805
2806
/************************************************************************
2807
 *                  *
2808
 *      Input/output callbacks        *
2809
 *                  *
2810
 ************************************************************************/
2811
2812
/**
2813
 * Initialize callback tables.
2814
 */
2815
void
2816
xmlInitIOCallbacks(void)
2817
10.4k
{
2818
10.4k
    xmlInputCallbackNr = 1;
2819
10.4k
    xmlInputCallbackTable[0].matchcallback = xmlIODefaultMatch;
2820
2821
10.4k
#ifdef LIBXML_OUTPUT_ENABLED
2822
10.4k
    xmlOutputCallbackNr = 1;
2823
10.4k
    xmlOutputCallbackTable[0].matchcallback = xmlIODefaultMatch;
2824
10.4k
#endif
2825
10.4k
}
2826
2827
/**
2828
 * Register a new set of I/O callback for handling parser input.
2829
 *
2830
 * @deprecated Use #xmlCtxtSetResourceLoader or similar functions.
2831
 *
2832
 * @param matchFunc  the xmlInputMatchCallback
2833
 * @param openFunc  the xmlInputOpenCallback
2834
 * @param readFunc  the xmlInputReadCallback
2835
 * @param closeFunc  the xmlInputCloseCallback
2836
 * @returns the registered handler number or -1 in case of error
2837
 */
2838
int
2839
xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2840
  xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2841
0
  xmlInputCloseCallback closeFunc) {
2842
0
    xmlInitParser();
2843
2844
0
    if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2845
0
  return(-1);
2846
0
    }
2847
0
    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2848
0
    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2849
0
    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2850
0
    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
2851
0
    return(xmlInputCallbackNr++);
2852
0
}
2853
2854
/**
2855
 * Registers the default compiled-in I/O handlers.
2856
 */
2857
void
2858
0
xmlRegisterDefaultInputCallbacks(void) {
2859
0
    xmlRegisterInputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
2860
0
}
2861
2862
/**
2863
 * Clear the top input callback from the input stack. this includes the
2864
 * compiled-in I/O.
2865
 *
2866
 * @returns the number of input callback registered or -1 in case of error.
2867
 */
2868
int
2869
xmlPopInputCallbacks(void)
2870
0
{
2871
0
    xmlInitParser();
2872
2873
0
    if (xmlInputCallbackNr <= 0)
2874
0
        return(-1);
2875
2876
0
    xmlInputCallbackNr--;
2877
2878
0
    return(xmlInputCallbackNr);
2879
0
}
2880
2881
/**
2882
 * clears the entire input callback table. this includes the
2883
 * compiled-in I/O.
2884
 */
2885
void
2886
xmlCleanupInputCallbacks(void)
2887
0
{
2888
0
    xmlInitParser();
2889
2890
0
    xmlInputCallbackNr = 0;
2891
0
}
2892
2893
#ifdef LIBXML_OUTPUT_ENABLED
2894
/**
2895
 * Register a new set of I/O callback for handling output.
2896
 *
2897
 * @param matchFunc  the xmlOutputMatchCallback
2898
 * @param openFunc  the xmlOutputOpenCallback
2899
 * @param writeFunc  the xmlOutputWriteCallback
2900
 * @param closeFunc  the xmlOutputCloseCallback
2901
 * @returns the registered handler number or -1 in case of error
2902
 */
2903
int
2904
xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2905
  xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2906
0
  xmlOutputCloseCallback closeFunc) {
2907
0
    xmlInitParser();
2908
2909
0
    if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
2910
0
  return(-1);
2911
0
    }
2912
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2913
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2914
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2915
0
    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
2916
0
    return(xmlOutputCallbackNr++);
2917
0
}
2918
2919
/**
2920
 * Registers the default compiled-in I/O handlers.
2921
 */
2922
void
2923
0
xmlRegisterDefaultOutputCallbacks (void) {
2924
0
    xmlRegisterOutputCallbacks(xmlIODefaultMatch, NULL, NULL, NULL);
2925
0
}
2926
2927
/**
2928
 * Remove the top output callbacks from the output stack. This includes the
2929
 * compiled-in I/O.
2930
 *
2931
 * @returns the number of output callback registered or -1 in case of error.
2932
 */
2933
int
2934
xmlPopOutputCallbacks(void)
2935
0
{
2936
0
    xmlInitParser();
2937
2938
0
    if (xmlOutputCallbackNr <= 0)
2939
0
        return(-1);
2940
2941
0
    xmlOutputCallbackNr--;
2942
2943
0
    return(xmlOutputCallbackNr);
2944
0
}
2945
2946
/**
2947
 * clears the entire output callback table. this includes the
2948
 * compiled-in I/O callbacks.
2949
 */
2950
void
2951
xmlCleanupOutputCallbacks(void)
2952
0
{
2953
0
    xmlInitParser();
2954
2955
0
    xmlOutputCallbackNr = 0;
2956
0
}
2957
#endif /* LIBXML_OUTPUT_ENABLED */
2958