Coverage Report

Created: 2025-10-10 06:45

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