Coverage Report

Created: 2024-09-06 07:53

/src/libxml2/buf.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * buf.c: memory buffers for libxml2
3
 *
4
 * new buffer structures and entry points to simplify the maintenance
5
 * of libxml2 and ensure we keep good control over memory allocations
6
 * and stay 64 bits clean.
7
 * The new entry point use the xmlBufPtr opaque structure and
8
 * xmlBuf...() counterparts to the old xmlBuf...() functions
9
 *
10
 * See Copyright for the status of this software.
11
 *
12
 * daniel@veillard.com
13
 */
14
15
#define IN_LIBXML
16
#include "libxml.h"
17
18
#include <string.h>
19
#include <limits.h>
20
21
#include <libxml/parser.h>
22
#include <libxml/tree.h>
23
24
#include "private/buf.h"
25
26
#ifndef SIZE_MAX
27
75.5k
#define SIZE_MAX ((size_t) -1)
28
#endif
29
30
#define WITH_BUFFER_COMPAT
31
32
4.77M
#define BUF_FLAG_OOM        (1u << 0)
33
4.77M
#define BUF_FLAG_OVERFLOW   (1u << 1)
34
2.91M
#define BUF_FLAG_STATIC     (1u << 2)
35
36
4.77M
#define BUF_ERROR(buf) ((buf)->flags & (BUF_FLAG_OOM | BUF_FLAG_OVERFLOW))
37
2.89M
#define BUF_STATIC(buf) ((buf)->flags & BUF_FLAG_STATIC)
38
39
/**
40
 * xmlBuf:
41
 *
42
 * A buffer structure. The base of the structure is somehow compatible
43
 * with struct _xmlBuffer to limit risks on application which accessed
44
 * directly the input->buf->buffer structures.
45
 */
46
47
struct _xmlBuf {
48
    xmlChar *content;   /* The buffer content UTF8 */
49
#ifdef WITH_BUFFER_COMPAT
50
    unsigned int compat_use;    /* for binary compatibility */
51
    unsigned int compat_size;   /* for binary compatibility */
52
#endif
53
    xmlChar *mem;   /* Start of the allocation */
54
    size_t use;           /* The buffer size used */
55
    size_t size;    /* The buffer size, excluding terminating 0 */
56
    size_t maxSize;             /* The maximum buffer size */
57
    unsigned flags;             /* flags */
58
};
59
60
#ifdef WITH_BUFFER_COMPAT
61
/*
62
 * Macro for compatibility with xmlBuffer to be used after an xmlBuf
63
 * is updated. This makes sure the compat fields are updated too.
64
 */
65
#define UPDATE_COMPAT(buf)            \
66
1.62M
     if (buf->size < INT_MAX) buf->compat_size = buf->size; \
67
1.62M
     else buf->compat_size = INT_MAX;         \
68
1.62M
     if (buf->use < INT_MAX) buf->compat_use = buf->use; \
69
1.62M
     else buf->compat_use = INT_MAX;
70
71
/*
72
 * Macro for compatibility with xmlBuffer to be used in all the xmlBuf
73
 * entry points, it checks that the compat fields have not been modified
74
 * by direct call to xmlBuffer function from code compiled before 2.9.0 .
75
 */
76
#define CHECK_COMPAT(buf)           \
77
6.13M
     if (buf->size != (size_t) buf->compat_size)     \
78
6.13M
         if (buf->compat_size < INT_MAX)       \
79
0
       buf->size = buf->compat_size;       \
80
6.13M
     if (buf->use != (size_t) buf->compat_use)       \
81
6.13M
         if (buf->compat_use < INT_MAX)         \
82
0
       buf->use = buf->compat_use;
83
84
#else /* ! WITH_BUFFER_COMPAT */
85
#define UPDATE_COMPAT(buf)
86
#define CHECK_COMPAT(buf)
87
#endif /* WITH_BUFFER_COMPAT */
88
89
/**
90
 * xmlBufMemoryError:
91
 * @extra:  extra information
92
 *
93
 * Handle an out of memory condition
94
 * To be improved...
95
 */
96
static void
97
xmlBufMemoryError(xmlBufPtr buf)
98
0
{
99
0
    if (!BUF_ERROR(buf))
100
0
        buf->flags |= BUF_FLAG_OOM;
101
0
}
102
103
/**
104
 * xmlBufOverflowError:
105
 * @extra:  extra information
106
 *
107
 * Handle a buffer overflow error
108
 * To be improved...
109
 */
110
static void
111
xmlBufOverflowError(xmlBufPtr buf)
112
0
{
113
0
    if (!BUF_ERROR(buf))
114
0
        buf->flags |= BUF_FLAG_OVERFLOW;
115
0
}
116
117
/**
118
 * xmlBufCreate:
119
 * @size: initial size of buffer
120
 *
121
 * routine to create an XML buffer.
122
 * returns the new structure.
123
 */
124
xmlBufPtr
125
28.4k
xmlBufCreate(size_t size) {
126
28.4k
    xmlBufPtr ret;
127
128
28.4k
    if (size == SIZE_MAX)
129
0
        return(NULL);
130
131
28.4k
    ret = xmlMalloc(sizeof(*ret));
132
28.4k
    if (ret == NULL)
133
0
        return(NULL);
134
135
28.4k
    ret->use = 0;
136
28.4k
    ret->flags = 0;
137
28.4k
    ret->size = size;
138
28.4k
    ret->maxSize = SIZE_MAX - 1;
139
140
28.4k
    ret->mem = xmlMalloc(ret->size + 1);
141
28.4k
    if (ret->mem == NULL) {
142
0
        xmlFree(ret);
143
0
        return(NULL);
144
0
    }
145
28.4k
    ret->content = ret->mem;
146
28.4k
    ret->content[0] = 0;
147
148
28.4k
    UPDATE_COMPAT(ret);
149
28.4k
    return(ret);
150
28.4k
}
151
152
/**
153
 * xmlBufCreateMem:
154
 * @mem:  a memory area
155
 * @size:  size of the buffer excluding terminator
156
 * @isStatic:  whether the memory area is static
157
 *
158
 * Create a buffer initialized with memory.
159
 *
160
 * If @isStatic is set, uses the memory area directly as backing store.
161
 * The memory must be zero-terminated and not be modified for the
162
 * lifetime of the buffer. A static buffer can't be grown, modified or
163
 * detached, but it can be shrunk.
164
 *
165
 * Returns a new buffer.
166
 */
167
xmlBufPtr
168
18.5k
xmlBufCreateMem(const xmlChar *mem, size_t size, int isStatic) {
169
18.5k
    xmlBufPtr ret;
170
171
18.5k
    if (mem == NULL)
172
0
        return(NULL);
173
174
18.5k
    ret = xmlMalloc(sizeof(*ret));
175
18.5k
    if (ret == NULL)
176
0
        return(NULL);
177
178
18.5k
    if (isStatic) {
179
        /* Check that memory is zero-terminated */
180
18.5k
        if (mem[size] != 0) {
181
0
            xmlFree(ret);
182
0
            return(NULL);
183
0
        }
184
18.5k
        ret->flags = BUF_FLAG_STATIC;
185
18.5k
        ret->mem = (xmlChar *) mem;
186
18.5k
    } else {
187
0
        ret->flags = 0;
188
0
        ret->mem = xmlMalloc(size + 1);
189
0
        if (ret->mem == NULL) {
190
0
            xmlFree(ret);
191
0
            return(NULL);
192
0
        }
193
0
        memcpy(ret->mem, mem, size);
194
0
        ret->mem[size] = 0;
195
0
    }
196
197
18.5k
    ret->use = size;
198
18.5k
    ret->size = size;
199
18.5k
    ret->maxSize = SIZE_MAX - 1;
200
18.5k
    ret->content = ret->mem;
201
202
18.5k
    UPDATE_COMPAT(ret);
203
18.5k
    return(ret);
204
18.5k
}
205
206
/**
207
 * xmlBufDetach:
208
 * @buf:  the buffer
209
 *
210
 * Remove the string contained in a buffer and give it back to the
211
 * caller. The buffer is reset to an empty content.
212
 * This doesn't work with immutable buffers as they can't be reset.
213
 *
214
 * Returns the previous string contained by the buffer.
215
 */
216
xmlChar *
217
5.90k
xmlBufDetach(xmlBufPtr buf) {
218
5.90k
    xmlChar *ret;
219
220
5.90k
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
221
0
        return(NULL);
222
223
5.90k
    if (buf->content != buf->mem) {
224
0
        ret = xmlStrndup(buf->content, buf->use);
225
0
        xmlFree(buf->mem);
226
5.90k
    } else {
227
5.90k
        ret = buf->mem;
228
5.90k
    }
229
230
5.90k
    buf->content = NULL;
231
5.90k
    buf->mem = NULL;
232
5.90k
    buf->size = 0;
233
5.90k
    buf->use = 0;
234
235
5.90k
    UPDATE_COMPAT(buf);
236
5.90k
    return ret;
237
5.90k
}
238
239
/**
240
 * xmlBufFree:
241
 * @buf:  the buffer to free
242
 *
243
 * Frees an XML buffer. It frees both the content and the structure which
244
 * encapsulate it.
245
 */
246
void
247
47.0k
xmlBufFree(xmlBufPtr buf) {
248
47.0k
    if (buf == NULL)
249
0
  return;
250
251
47.0k
    if (!BUF_STATIC(buf))
252
28.4k
        xmlFree(buf->mem);
253
47.0k
    xmlFree(buf);
254
47.0k
}
255
256
/**
257
 * xmlBufEmpty:
258
 * @buf:  the buffer
259
 *
260
 * empty a buffer.
261
 */
262
void
263
0
xmlBufEmpty(xmlBufPtr buf) {
264
0
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
265
0
        return;
266
0
    if (buf->mem == NULL)
267
0
        return;
268
0
    CHECK_COMPAT(buf)
269
270
0
    buf->use = 0;
271
0
    buf->size += buf->content - buf->mem;
272
0
    buf->content = buf->mem;
273
0
    buf->content[0] = 0;
274
275
0
    UPDATE_COMPAT(buf)
276
0
}
277
278
/**
279
 * xmlBufShrink:
280
 * @buf:  the buffer to dump
281
 * @len:  the number of xmlChar to remove
282
 *
283
 * DEPRECATED: Don't use.
284
 *
285
 * Remove the beginning of an XML buffer.
286
 * NOTE that this routine behaviour differs from xmlBufferShrink()
287
 * as it will return 0 on error instead of -1 due to size_t being
288
 * used as the return type.
289
 *
290
 * Returns the number of byte removed or 0 in case of failure
291
 */
292
size_t
293
85.2k
xmlBufShrink(xmlBufPtr buf, size_t len) {
294
85.2k
    if ((buf == NULL) || (BUF_ERROR(buf)))
295
0
        return(0);
296
85.2k
    if (len == 0)
297
15.7k
        return(0);
298
69.4k
    CHECK_COMPAT(buf)
299
300
69.4k
    if (len > buf->use)
301
0
        return(0);
302
303
69.4k
    buf->use -= len;
304
69.4k
    buf->content += len;
305
69.4k
    buf->size -= len;
306
307
69.4k
    UPDATE_COMPAT(buf)
308
69.4k
    return(len);
309
69.4k
}
310
311
/**
312
 * xmlBufGrowInternal:
313
 * @buf:  the buffer
314
 * @len:  the minimum free size to allocate
315
 *
316
 * Grow the available space of an XML buffer, @len is the target value
317
 *
318
 * Returns 0 on success, -1 in case of error
319
 */
320
static int
321
47.2k
xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
322
47.2k
    size_t size;
323
47.2k
    size_t start;
324
47.2k
    xmlChar *newbuf;
325
326
    /*
327
     * If there's enough space at the start of the buffer,
328
     * move the contents.
329
     */
330
47.2k
    start = buf->content - buf->mem;
331
47.2k
    if (len <= start + buf->size - buf->use) {
332
36.8k
        memmove(buf->mem, buf->content, buf->use + 1);
333
36.8k
        buf->size += start;
334
36.8k
        buf->content = buf->mem;
335
36.8k
        return(0);
336
36.8k
    }
337
338
10.3k
    if (len > buf->maxSize - buf->use) {
339
0
        xmlBufOverflowError(buf);
340
0
        return(-1);
341
0
    }
342
343
10.3k
    if (buf->size > (size_t) len) {
344
7.11k
        if (buf->size <= buf->maxSize / 2)
345
7.11k
            size = buf->size * 2;
346
0
        else
347
0
            size = buf->maxSize;
348
7.11k
    } else {
349
3.26k
        size = buf->use + len;
350
3.26k
        if (size <= buf->maxSize - 100)
351
3.26k
            size += 100;
352
3.26k
    }
353
354
10.3k
    if (buf->content == buf->mem) {
355
9.29k
        newbuf = xmlRealloc(buf->mem, size + 1);
356
9.29k
        if (newbuf == NULL) {
357
0
            xmlBufMemoryError(buf);
358
0
            return(-1);
359
0
        }
360
9.29k
    } else {
361
1.09k
        newbuf = xmlMalloc(size + 1);
362
1.09k
        if (newbuf == NULL) {
363
0
            xmlBufMemoryError(buf);
364
0
            return(-1);
365
0
        }
366
1.09k
        if (buf->content != NULL)
367
1.09k
            memcpy(newbuf, buf->content, buf->use + 1);
368
1.09k
        xmlFree(buf->mem);
369
1.09k
    }
370
371
10.3k
    buf->mem = newbuf;
372
10.3k
    buf->content = newbuf;
373
10.3k
    buf->size = size;
374
375
10.3k
    return(0);
376
10.3k
}
377
378
/**
379
 * xmlBufGrow:
380
 * @buf:  the buffer
381
 * @len:  the minimum free size to allocate
382
 *
383
 * Grow the available space of an XML buffer, @len is the target value
384
 * This is been kept compatible with xmlBufferGrow() as much as possible
385
 *
386
 * Returns 0 on succes, -1 in case of error
387
 */
388
int
389
1.38M
xmlBufGrow(xmlBufPtr buf, size_t len) {
390
1.38M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
391
0
        return(-1);
392
1.38M
    CHECK_COMPAT(buf)
393
394
1.38M
    if (len <= buf->size - buf->use)
395
1.34M
        return(0);
396
397
43.8k
    if (xmlBufGrowInternal(buf, len) < 0)
398
0
        return(-1);
399
400
43.8k
    UPDATE_COMPAT(buf)
401
43.8k
    return(0);
402
43.8k
}
403
404
/**
405
 * xmlBufContent:
406
 * @buf:  the buffer
407
 *
408
 * Function to extract the content of a buffer
409
 *
410
 * Returns the internal content
411
 */
412
413
xmlChar *
414
xmlBufContent(const xmlBuf *buf)
415
57.8k
{
416
57.8k
    if ((!buf) || (BUF_ERROR(buf)))
417
0
        return NULL;
418
419
57.8k
    return(buf->content);
420
57.8k
}
421
422
/**
423
 * xmlBufEnd:
424
 * @buf:  the buffer
425
 *
426
 * Function to extract the end of the content of a buffer
427
 *
428
 * Returns the end of the internal content or NULL in case of error
429
 */
430
431
xmlChar *
432
xmlBufEnd(xmlBufPtr buf)
433
1.44M
{
434
1.44M
    if ((!buf) || (BUF_ERROR(buf)))
435
0
        return NULL;
436
1.44M
    CHECK_COMPAT(buf)
437
438
1.44M
    return(&buf->content[buf->use]);
439
1.44M
}
440
441
/**
442
 * xmlBufAddLen:
443
 * @buf:  the buffer
444
 * @len:  the size which were added at the end
445
 *
446
 * Sometime data may be added at the end of the buffer without
447
 * using the xmlBuf APIs that is used to expand the used space
448
 * and set the zero terminating at the end of the buffer
449
 *
450
 * Returns -1 in case of error and 0 otherwise
451
 */
452
int
453
1.44M
xmlBufAddLen(xmlBufPtr buf, size_t len) {
454
1.44M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
455
0
        return(-1);
456
1.44M
    CHECK_COMPAT(buf)
457
1.44M
    if (len > buf->size - buf->use)
458
0
        return(-1);
459
1.44M
    buf->use += len;
460
1.44M
    buf->content[buf->use] = 0;
461
1.44M
    UPDATE_COMPAT(buf)
462
1.44M
    return(0);
463
1.44M
}
464
465
/**
466
 * xmlBufUse:
467
 * @buf:  the buffer
468
 *
469
 * Function to get the length of a buffer
470
 *
471
 * Returns the length of data in the internal content
472
 */
473
474
size_t
475
xmlBufUse(const xmlBufPtr buf)
476
258k
{
477
258k
    if ((!buf) || (BUF_ERROR(buf)))
478
0
        return 0;
479
258k
    CHECK_COMPAT(buf)
480
481
258k
    return(buf->use);
482
258k
}
483
484
/**
485
 * xmlBufAvail:
486
 * @buf:  the buffer
487
 *
488
 * Function to find how much free space is allocated but not
489
 * used in the buffer. It reserves one byte for the NUL
490
 * terminator character that is usually needed, so there is
491
 * no need to subtract 1 from the result anymore.
492
 *
493
 * Returns the amount, or 0 if none or if an error occurred.
494
 */
495
496
size_t
497
xmlBufAvail(const xmlBufPtr buf)
498
66.4k
{
499
66.4k
    if ((!buf) || (BUF_ERROR(buf)))
500
0
        return 0;
501
66.4k
    CHECK_COMPAT(buf)
502
503
66.4k
    return(buf->size - buf->use);
504
66.4k
}
505
506
/**
507
 * xmlBufIsEmpty:
508
 * @buf:  the buffer
509
 *
510
 * Tell if a buffer is empty
511
 *
512
 * Returns 0 if no, 1 if yes and -1 in case of error
513
 */
514
int
515
xmlBufIsEmpty(const xmlBufPtr buf)
516
10.9k
{
517
10.9k
    if ((!buf) || (BUF_ERROR(buf)))
518
0
        return(-1);
519
10.9k
    CHECK_COMPAT(buf)
520
521
10.9k
    return(buf->use == 0);
522
10.9k
}
523
524
/**
525
 * xmlBufAdd:
526
 * @buf:  the buffer to dump
527
 * @str:  the #xmlChar string
528
 * @len:  the number of #xmlChar to add
529
 *
530
 * Add a string range to an XML buffer. if len == -1, the length of
531
 * str is recomputed.
532
 *
533
 * Returns 0 if successful, -1 in case of error.
534
 */
535
int
536
11.0k
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, size_t len) {
537
11.0k
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
538
0
        return(-1);
539
11.0k
    if (len == 0)
540
0
        return(0);
541
11.0k
    if (str == NULL)
542
0
  return(-1);
543
11.0k
    CHECK_COMPAT(buf)
544
545
11.0k
    if (len > buf->size - buf->use) {
546
3.44k
        if (xmlBufGrowInternal(buf, len) < 0)
547
0
            return(-1);
548
3.44k
    }
549
550
11.0k
    memmove(&buf->content[buf->use], str, len);
551
11.0k
    buf->use += len;
552
11.0k
    buf->content[buf->use] = 0;
553
554
11.0k
    UPDATE_COMPAT(buf)
555
11.0k
    return(0);
556
11.0k
}
557
558
/**
559
 * xmlBufCat:
560
 * @buf:  the buffer to add to
561
 * @str:  the #xmlChar string (optional)
562
 *
563
 * Append a zero terminated string to an XML buffer.
564
 *
565
 * Returns 0 successful, a positive error code number otherwise
566
 *         and -1 in case of internal or API error.
567
 */
568
int
569
3.03k
xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
570
3.03k
    if (str == NULL)
571
0
        return(0);
572
3.03k
    return(xmlBufAdd(buf, str, strlen((const char *) str)));
573
3.03k
}
574
575
/**
576
 * xmlBufFromBuffer:
577
 * @buffer: incoming old buffer to convert to a new one
578
 *
579
 * Helper routine to switch from the old buffer structures in use
580
 * in various APIs. It creates a wrapper xmlBufPtr which will be
581
 * used for internal processing until the xmlBufBackToBuffer() is
582
 * issued.
583
 *
584
 * Returns a new xmlBufPtr unless the call failed and NULL is returned
585
 */
586
xmlBufPtr
587
0
xmlBufFromBuffer(xmlBufferPtr buffer) {
588
0
    xmlBufPtr ret;
589
590
0
    if (buffer == NULL)
591
0
        return(NULL);
592
593
0
    ret = xmlMalloc(sizeof(xmlBuf));
594
0
    if (ret == NULL)
595
0
        return(NULL);
596
597
0
    ret->use = buffer->use;
598
0
    ret->flags = 0;
599
0
    ret->maxSize = SIZE_MAX - 1;
600
601
0
    if (buffer->content == NULL) {
602
0
        ret->size = 50;
603
0
        ret->mem = xmlMalloc(ret->size + 1);
604
0
        ret->content = ret->mem;
605
0
        if (ret->mem == NULL)
606
0
            xmlBufMemoryError(ret);
607
0
        else
608
0
            ret->content[0] = 0;
609
0
    } else {
610
0
        ret->size = buffer->size - 1;
611
0
        ret->content = buffer->content;
612
0
        if (buffer->alloc == XML_BUFFER_ALLOC_IO)
613
0
            ret->mem = buffer->contentIO;
614
0
        else
615
0
            ret->mem = buffer->content;
616
0
    }
617
618
0
    UPDATE_COMPAT(ret);
619
0
    return(ret);
620
0
}
621
622
/**
623
 * xmlBufBackToBuffer:
624
 * @buf: new buffer wrapping the old one
625
 *
626
 * Function to be called once internal processing had been done to
627
 * update back the buffer provided by the user. This can lead to
628
 * a failure in case the size accumulated in the xmlBuf is larger
629
 * than what an xmlBuffer can support on 64 bits (INT_MAX)
630
 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
631
 *
632
 * Returns the old xmlBufferPtr unless the call failed and NULL is returned
633
 */
634
int
635
0
xmlBufBackToBuffer(xmlBufPtr buf, xmlBufferPtr ret) {
636
0
    if ((buf == NULL) || (ret == NULL))
637
0
        return(-1);
638
639
0
    if ((BUF_ERROR(buf)) || (BUF_STATIC(buf)) ||
640
0
        (buf->use >= INT_MAX)) {
641
0
        xmlBufFree(buf);
642
0
        ret->content = NULL;
643
0
        ret->contentIO = NULL;
644
0
        ret->use = 0;
645
0
        ret->size = 0;
646
0
        return(-1);
647
0
    }
648
649
0
    ret->use = buf->use;
650
0
    if (buf->size >= INT_MAX) {
651
        /* Keep the buffer but provide a truncated size value. */
652
0
        ret->size = INT_MAX;
653
0
    } else {
654
0
        ret->size = buf->size + 1;
655
0
    }
656
0
    ret->alloc = XML_BUFFER_ALLOC_IO;
657
0
    ret->content = buf->content;
658
0
    ret->contentIO = buf->mem;
659
0
    xmlFree(buf);
660
0
    return(0);
661
0
}
662
663
/**
664
 * xmlBufResetInput:
665
 * @buf: an xmlBufPtr
666
 * @input: an xmlParserInputPtr
667
 *
668
 * Update the input to use the current set of pointers from the buffer.
669
 *
670
 * Returns -1 in case of error, 0 otherwise
671
 */
672
int
673
41.8k
xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
674
41.8k
    return(xmlBufUpdateInput(buf, input, 0));
675
41.8k
}
676
677
/**
678
 * xmlBufUpdateInput:
679
 * @buf: an xmlBufPtr
680
 * @input: an xmlParserInputPtr
681
 * @pos: the cur value relative to the beginning of the buffer
682
 *
683
 * Update the input to use the base and cur relative to the buffer
684
 * after a possible reallocation of its content
685
 *
686
 * Returns -1 in case of error, 0 otherwise
687
 */
688
int
689
1.44M
xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
690
1.44M
    if ((buf == NULL) || (input == NULL))
691
0
        return(-1);
692
1.44M
    CHECK_COMPAT(buf)
693
1.44M
    input->base = buf->content;
694
1.44M
    input->cur = input->base + pos;
695
1.44M
    input->end = &buf->content[buf->use];
696
1.44M
    return(0);
697
1.44M
}
698
699
/************************************************************************
700
 *                  *
701
 *      Old buffer implementation     *
702
 *                  *
703
 ************************************************************************/
704
705
/**
706
 * xmlSetBufferAllocationScheme:
707
 * @scheme:  allocation method to use
708
 *
709
 * DEPRECATED: Use xmlBufferSetAllocationScheme.
710
 *
711
 * Set the buffer allocation method.  Types are
712
 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
713
 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
714
 *                             improves performance
715
 */
716
void
717
0
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme ATTRIBUTE_UNUSED) {
718
0
}
719
720
/**
721
 * xmlGetBufferAllocationScheme:
722
 *
723
 * DEPRECATED: Use xmlBufferSetAllocationScheme.
724
 *
725
 * Types are
726
 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
727
 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
728
 *                             improves performance
729
 * XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
730
 *                            in normal usage, and doubleit on large strings to avoid
731
 *                            pathological performance.
732
 *
733
 * Returns the current allocation scheme
734
 */
735
xmlBufferAllocationScheme
736
0
xmlGetBufferAllocationScheme(void) {
737
0
    return(XML_BUFFER_ALLOC_EXACT);
738
0
}
739
740
/**
741
 * xmlBufferCreate:
742
 *
743
 * routine to create an XML buffer.
744
 * returns the new structure.
745
 */
746
xmlBufferPtr
747
0
xmlBufferCreate(void) {
748
0
    xmlBufferPtr ret;
749
750
0
    ret = xmlMalloc(sizeof(*ret));
751
0
    if (ret == NULL)
752
0
        return(NULL);
753
754
0
    ret->use = 0;
755
0
    ret->size = 256;
756
0
    ret->alloc = XML_BUFFER_ALLOC_IO;
757
0
    ret->contentIO = xmlMalloc(ret->size);
758
0
    if (ret->contentIO == NULL) {
759
0
  xmlFree(ret);
760
0
        return(NULL);
761
0
    }
762
0
    ret->content = ret->contentIO;
763
0
    ret->content[0] = 0;
764
765
0
    return(ret);
766
0
}
767
768
/**
769
 * xmlBufferCreateSize:
770
 * @size: initial size of buffer
771
 *
772
 * routine to create an XML buffer.
773
 * returns the new structure.
774
 */
775
xmlBufferPtr
776
0
xmlBufferCreateSize(size_t size) {
777
0
    xmlBufferPtr ret;
778
779
0
    if (size >= INT_MAX)
780
0
        return(NULL);
781
782
0
    ret = xmlMalloc(sizeof(*ret));
783
0
    if (ret == NULL)
784
0
        return(NULL);
785
786
0
    ret->use = 0;
787
0
    ret->alloc = XML_BUFFER_ALLOC_IO;
788
0
    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
789
790
0
    if (ret->size) {
791
0
        ret->contentIO = xmlMalloc(ret->size);
792
0
        if (ret->contentIO == NULL) {
793
0
            xmlFree(ret);
794
0
            return(NULL);
795
0
        }
796
0
        ret->content = ret->contentIO;
797
0
        ret->content[0] = 0;
798
0
    } else {
799
0
        ret->contentIO = NULL;
800
0
  ret->content = NULL;
801
0
    }
802
803
0
    return(ret);
804
0
}
805
806
/**
807
 * xmlBufferDetach:
808
 * @buf:  the buffer
809
 *
810
 * Remove the string contained in a buffer and gie it back to the
811
 * caller. The buffer is reset to an empty content.
812
 * This doesn't work with immutable buffers as they can't be reset.
813
 *
814
 * Returns the previous string contained by the buffer.
815
 */
816
xmlChar *
817
0
xmlBufferDetach(xmlBufferPtr buf) {
818
0
    xmlChar *ret;
819
820
0
    if (buf == NULL)
821
0
        return(NULL);
822
823
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
824
0
        (buf->content != buf->contentIO)) {
825
0
        ret = xmlStrndup(buf->content, buf->use);
826
0
        xmlFree(buf->contentIO);
827
0
    } else {
828
0
        ret = buf->content;
829
0
    }
830
831
0
    buf->contentIO = NULL;
832
0
    buf->content = NULL;
833
0
    buf->size = 0;
834
0
    buf->use = 0;
835
836
0
    return ret;
837
0
}
838
839
/**
840
 * xmlBufferCreateStatic:
841
 * @mem: the memory area
842
 * @size:  the size in byte
843
 *
844
 * Returns an XML buffer initialized with bytes.
845
 */
846
xmlBufferPtr
847
0
xmlBufferCreateStatic(void *mem, size_t size) {
848
0
    xmlBufferPtr buf = xmlBufferCreateSize(size);
849
850
0
    xmlBufferAdd(buf, mem, size);
851
0
    return(buf);
852
0
}
853
854
/**
855
 * xmlBufferSetAllocationScheme:
856
 * @buf:  the buffer to tune
857
 * @scheme:  allocation scheme to use
858
 *
859
 * Sets the allocation scheme for this buffer.
860
 *
861
 * For libxml2 before 2.14, it is recommended to set this to
862
 * XML_BUFFER_ALLOC_DOUBLE_IT. Has no effect on 2.14 or later.
863
 */
864
void
865
xmlBufferSetAllocationScheme(xmlBufferPtr buf ATTRIBUTE_UNUSED,
866
0
                             xmlBufferAllocationScheme scheme ATTRIBUTE_UNUSED) {
867
0
}
868
869
/**
870
 * xmlBufferFree:
871
 * @buf:  the buffer to free
872
 *
873
 * Frees an XML buffer. It frees both the content and the structure which
874
 * encapsulate it.
875
 */
876
void
877
0
xmlBufferFree(xmlBufferPtr buf) {
878
0
    if (buf == NULL)
879
0
  return;
880
881
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
882
0
        xmlFree(buf->contentIO);
883
0
    else
884
0
        xmlFree(buf->content);
885
886
0
    xmlFree(buf);
887
0
}
888
889
/**
890
 * xmlBufferEmpty:
891
 * @buf:  the buffer
892
 *
893
 * empty a buffer.
894
 */
895
void
896
0
xmlBufferEmpty(xmlBufferPtr buf) {
897
0
    if (buf == NULL)
898
0
        return;
899
0
    if (buf->content == NULL)
900
0
        return;
901
902
0
    buf->use = 0;
903
904
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
905
0
  buf->size += buf->content - buf->contentIO;
906
0
        buf->content = buf->contentIO;
907
0
        buf->content[0] = 0;
908
0
    } else {
909
0
        buf->content[0] = 0;
910
0
    }
911
0
}
912
913
/**
914
 * xmlBufferShrink:
915
 * @buf:  the buffer to dump
916
 * @len:  the number of xmlChar to remove
917
 *
918
 * DEPRECATED: Don't use.
919
 *
920
 * Remove the beginning of an XML buffer.
921
 *
922
 * Returns the number of #xmlChar removed, or -1 in case of failure.
923
 */
924
int
925
0
xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
926
0
    if (buf == NULL)
927
0
        return(-1);
928
0
    if (len == 0)
929
0
        return(0);
930
0
    if (len > buf->use)
931
0
        return(-1);
932
933
0
    buf->use -= len;
934
935
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
936
0
        buf->content += len;
937
0
  buf->size -= len;
938
0
    } else {
939
0
  memmove(buf->content, &buf->content[len], buf->use + 1);
940
0
    }
941
942
0
    return(len);
943
0
}
944
945
/**
946
 * xmlBufferGrow:
947
 * @buf:  the buffer
948
 * @len:  the minimum free size to allocate
949
 *
950
 * DEPRECATED: Don't use.
951
 *
952
 * Grow the available space of an XML buffer.
953
 *
954
 * Returns the new available space or -1 in case of error
955
 */
956
int
957
0
xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
958
0
    unsigned int size;
959
0
    xmlChar *newbuf;
960
961
0
    if (buf == NULL)
962
0
        return(-1);
963
964
0
    if (len < buf->size - buf->use)
965
0
        return(0);
966
0
    if (len >= INT_MAX - buf->use)
967
0
        return(-1);
968
969
0
    if (buf->size > (size_t) len) {
970
0
        if (buf->size <= INT_MAX / 2)
971
0
            size = buf->size * 2;
972
0
        else
973
0
            size = INT_MAX;
974
0
    } else {
975
0
        size = buf->use + len + 1;
976
0
        if (size <= INT_MAX - 100)
977
0
            size += 100;
978
0
    }
979
980
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
981
0
        (buf->content != buf->contentIO)) {
982
0
        newbuf = xmlMalloc(size);
983
0
        if (newbuf == NULL)
984
0
            return(-1);
985
0
        if (buf->content != NULL)
986
0
            memcpy(newbuf, buf->content, buf->use + 1);
987
0
        xmlFree(buf->contentIO);
988
0
    } else {
989
0
        newbuf = xmlRealloc(buf->content, size);
990
0
        if (newbuf == NULL)
991
0
            return(-1);
992
0
    }
993
994
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
995
0
        buf->contentIO = newbuf;
996
0
    buf->content = newbuf;
997
0
    buf->size = size;
998
999
0
    return(buf->size - buf->use - 1);
1000
0
}
1001
1002
/**
1003
 * xmlBufferDump:
1004
 * @file:  the file output
1005
 * @buf:  the buffer to dump
1006
 *
1007
 * Dumps an XML buffer to  a FILE *.
1008
 * Returns the number of #xmlChar written
1009
 */
1010
int
1011
0
xmlBufferDump(FILE *file, xmlBufferPtr buf) {
1012
0
    size_t ret;
1013
1014
0
    if (buf == NULL)
1015
0
  return(0);
1016
0
    if (buf->content == NULL)
1017
0
  return(0);
1018
0
    if (file == NULL)
1019
0
  file = stdout;
1020
0
    ret = fwrite(buf->content, 1, buf->use, file);
1021
0
    return(ret > INT_MAX ? INT_MAX : ret);
1022
0
}
1023
1024
/**
1025
 * xmlBufferContent:
1026
 * @buf:  the buffer
1027
 *
1028
 * Function to extract the content of a buffer
1029
 *
1030
 * Returns the internal content
1031
 */
1032
1033
const xmlChar *
1034
xmlBufferContent(const xmlBuffer *buf)
1035
0
{
1036
0
    if(!buf)
1037
0
        return NULL;
1038
1039
0
    return buf->content;
1040
0
}
1041
1042
/**
1043
 * xmlBufferLength:
1044
 * @buf:  the buffer
1045
 *
1046
 * Function to get the length of a buffer
1047
 *
1048
 * Returns the length of data in the internal content
1049
 */
1050
1051
int
1052
xmlBufferLength(const xmlBuffer *buf)
1053
0
{
1054
0
    if(!buf)
1055
0
        return 0;
1056
1057
0
    return buf->use;
1058
0
}
1059
1060
/**
1061
 * xmlBufferResize:
1062
 * @buf:  the buffer to resize
1063
 * @size:  the desired size
1064
 *
1065
 * DEPRECATED: Don't use.
1066
1067
 * Resize a buffer to accommodate minimum size of @size.
1068
 *
1069
 * Returns  0 in case of problems, 1 otherwise
1070
 */
1071
int
1072
xmlBufferResize(xmlBufferPtr buf, unsigned int size)
1073
0
{
1074
0
    int res;
1075
1076
0
    if (buf == NULL)
1077
0
        return(0);
1078
0
    if (size < buf->size)
1079
0
        return(1);
1080
0
    res = xmlBufferGrow(buf, size - buf->use);
1081
1082
0
    return(res < 0 ? 0 : 1);
1083
0
}
1084
1085
/**
1086
 * xmlBufferAdd:
1087
 * @buf:  the buffer to dump
1088
 * @str:  the #xmlChar string
1089
 * @len:  the number of #xmlChar to add
1090
 *
1091
 * Add a string range to an XML buffer. if len == -1, the length of
1092
 * str is recomputed.
1093
 *
1094
 * Returns a xmlParserError code.
1095
 */
1096
int
1097
0
xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
1098
0
    if ((buf == NULL) || (str == NULL))
1099
0
  return(XML_ERR_ARGUMENT);
1100
0
    if (len < 0)
1101
0
        len = xmlStrlen(str);
1102
0
    if (len == 0)
1103
0
        return(XML_ERR_OK);
1104
1105
    /* Note that both buf->size and buf->use can be zero here. */
1106
0
    if ((unsigned) len >= buf->size - buf->use) {
1107
0
        if (xmlBufferGrow(buf, len) < 0)
1108
0
            return(XML_ERR_NO_MEMORY);
1109
0
    }
1110
1111
0
    memmove(&buf->content[buf->use], str, len);
1112
0
    buf->use += len;
1113
0
    buf->content[buf->use] = 0;
1114
0
    return(XML_ERR_OK);
1115
0
}
1116
1117
/**
1118
 * xmlBufferAddHead:
1119
 * @buf:  the buffer
1120
 * @str:  the #xmlChar string
1121
 * @len:  the number of #xmlChar to add
1122
 *
1123
 * Add a string range to the beginning of an XML buffer.
1124
 * if len == -1, the length of @str is recomputed.
1125
 *
1126
 * Returns a xmlParserError code.
1127
 */
1128
int
1129
0
xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
1130
0
    unsigned start = 0;
1131
1132
0
    if ((buf == NULL) || (str == NULL))
1133
0
  return(XML_ERR_ARGUMENT);
1134
0
    if (len < 0)
1135
0
        len = xmlStrlen(str);
1136
0
    if (len == 0)
1137
0
        return(XML_ERR_OK);
1138
1139
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
1140
0
        start = buf->content - buf->contentIO;
1141
1142
        /*
1143
         * We can add it in the space previously shrunk
1144
         */
1145
0
        if ((unsigned) len <= start) {
1146
0
            buf->content -= len;
1147
0
            memmove(&buf->content[0], str, len);
1148
0
            buf->use += len;
1149
0
            buf->size += len;
1150
0
            return(0);
1151
0
        }
1152
0
        if ((unsigned) len < buf->size + start - buf->use) {
1153
0
            memmove(&buf->contentIO[len], buf->content, buf->use + 1);
1154
0
            memmove(buf->contentIO, str, len);
1155
0
            buf->content = buf->contentIO;
1156
0
            buf->use += len;
1157
0
            buf->size += start;
1158
0
            return(0);
1159
0
        }
1160
0
    }
1161
1162
0
    if ((unsigned) len >= buf->size - buf->use) {
1163
0
        if (xmlBufferGrow(buf, len) < 0)
1164
0
            return(-1);
1165
0
    }
1166
1167
0
    memmove(&buf->content[len], buf->content, buf->use + 1);
1168
0
    memmove(buf->content, str, len);
1169
0
    buf->use += len;
1170
0
    return (0);
1171
0
}
1172
1173
/**
1174
 * xmlBufferCat:
1175
 * @buf:  the buffer to add to
1176
 * @str:  the #xmlChar string
1177
 *
1178
 * Append a zero terminated string to an XML buffer.
1179
 *
1180
 * Returns 0 successful, a positive error code number otherwise
1181
 *         and -1 in case of internal or API error.
1182
 */
1183
int
1184
0
xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
1185
0
    return(xmlBufferAdd(buf, str, -1));
1186
0
}
1187
1188
/**
1189
 * xmlBufferCCat:
1190
 * @buf:  the buffer to dump
1191
 * @str:  the C char string
1192
 *
1193
 * Append a zero terminated C string to an XML buffer.
1194
 *
1195
 * Returns 0 successful, a positive error code number otherwise
1196
 *         and -1 in case of internal or API error.
1197
 */
1198
int
1199
0
xmlBufferCCat(xmlBufferPtr buf, const char *str) {
1200
0
    return(xmlBufferAdd(buf, (const xmlChar *) str, -1));
1201
0
}
1202
1203
/**
1204
 * xmlBufferWriteCHAR:
1205
 * @buf:  the XML buffer
1206
 * @string:  the string to add
1207
 *
1208
 * routine which manages and grows an output buffer. This one adds
1209
 * xmlChars at the end of the buffer.
1210
 */
1211
void
1212
0
xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
1213
0
    xmlBufferAdd(buf, string, -1);
1214
0
}
1215
1216
/**
1217
 * xmlBufferWriteChar:
1218
 * @buf:  the XML buffer output
1219
 * @string:  the string to add
1220
 *
1221
 * routine which manage and grows an output buffer. This one add
1222
 * C chars at the end of the array.
1223
 */
1224
void
1225
0
xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
1226
0
    xmlBufferAdd(buf, (const xmlChar *) string, -1);
1227
0
}
1228
1229
1230
/**
1231
 * xmlBufferWriteQuotedString:
1232
 * @buf:  the XML buffer output
1233
 * @string:  the string to add
1234
 *
1235
 * routine which manage and grows an output buffer. This one writes
1236
 * a quoted or double quoted #xmlChar string, checking first if it holds
1237
 * quote or double-quotes internally
1238
 */
1239
void
1240
0
xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
1241
0
    const xmlChar *cur, *base;
1242
0
    if (buf == NULL)
1243
0
        return;
1244
0
    if (xmlStrchr(string, '\"')) {
1245
0
        if (xmlStrchr(string, '\'')) {
1246
0
      xmlBufferCCat(buf, "\"");
1247
0
            base = cur = string;
1248
0
            while(*cur != 0){
1249
0
                if(*cur == '"'){
1250
0
                    if (base != cur)
1251
0
                        xmlBufferAdd(buf, base, cur - base);
1252
0
                    xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
1253
0
                    cur++;
1254
0
                    base = cur;
1255
0
                }
1256
0
                else {
1257
0
                    cur++;
1258
0
                }
1259
0
            }
1260
0
            if (base != cur)
1261
0
                xmlBufferAdd(buf, base, cur - base);
1262
0
      xmlBufferCCat(buf, "\"");
1263
0
  }
1264
0
        else{
1265
0
      xmlBufferCCat(buf, "\'");
1266
0
            xmlBufferCat(buf, string);
1267
0
      xmlBufferCCat(buf, "\'");
1268
0
        }
1269
0
    } else {
1270
0
        xmlBufferCCat(buf, "\"");
1271
0
        xmlBufferCat(buf, string);
1272
0
        xmlBufferCCat(buf, "\"");
1273
0
    }
1274
0
}
1275