Coverage Report

Created: 2025-07-18 06:31

/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
#define SIZE_MAX ((size_t) -1)
28
#endif
29
30
#define WITH_BUFFER_COMPAT
31
32
789M
#define BUF_FLAG_OOM        (1u << 0)
33
789M
#define BUF_FLAG_OVERFLOW   (1u << 1)
34
278M
#define BUF_FLAG_STATIC     (1u << 2)
35
36
789M
#define BUF_ERROR(buf) ((buf)->flags & (BUF_FLAG_OOM | BUF_FLAG_OVERFLOW))
37
278M
#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
294M
     if (buf->size < INT_MAX) buf->compat_size = buf->size; \
67
294M
     else buf->compat_size = INT_MAX;         \
68
294M
     if (buf->use < INT_MAX) buf->compat_use = buf->use; \
69
294M
     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
677M
     if (buf->size != (size_t) buf->compat_size)     \
78
677M
         if (buf->compat_size < INT_MAX)       \
79
0
       buf->size = buf->compat_size;       \
80
677M
     if (buf->use != (size_t) buf->compat_use)       \
81
677M
         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
96
{
99
96
    if (!BUF_ERROR(buf))
100
96
        buf->flags |= BUF_FLAG_OOM;
101
96
}
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
1.22M
xmlBufCreate(size_t size) {
126
1.22M
    xmlBufPtr ret;
127
128
1.22M
    if (size == SIZE_MAX)
129
0
        return(NULL);
130
131
1.22M
    ret = xmlMalloc(sizeof(*ret));
132
1.22M
    if (ret == NULL)
133
4.06k
        return(NULL);
134
135
1.22M
    ret->use = 0;
136
1.22M
    ret->flags = 0;
137
1.22M
    ret->size = size;
138
1.22M
    ret->maxSize = SIZE_MAX - 1;
139
140
1.22M
    ret->mem = xmlMalloc(ret->size + 1);
141
1.22M
    if (ret->mem == NULL) {
142
137
        xmlFree(ret);
143
137
        return(NULL);
144
137
    }
145
1.22M
    ret->content = ret->mem;
146
1.22M
    ret->content[0] = 0;
147
148
1.22M
    UPDATE_COMPAT(ret);
149
1.22M
    return(ret);
150
1.22M
}
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
859k
xmlBufCreateMem(const xmlChar *mem, size_t size, int isStatic) {
169
859k
    xmlBufPtr ret;
170
171
859k
    if (mem == NULL)
172
0
        return(NULL);
173
174
859k
    ret = xmlMalloc(sizeof(*ret));
175
859k
    if (ret == NULL)
176
39
        return(NULL);
177
178
859k
    if (isStatic) {
179
        /* Check that memory is zero-terminated */
180
8.32k
        if (mem[size] != 0) {
181
0
            xmlFree(ret);
182
0
            return(NULL);
183
0
        }
184
8.32k
        ret->flags = BUF_FLAG_STATIC;
185
8.32k
        ret->mem = (xmlChar *) mem;
186
851k
    } else {
187
851k
        ret->flags = 0;
188
851k
        ret->mem = xmlMalloc(size + 1);
189
851k
        if (ret->mem == NULL) {
190
57
            xmlFree(ret);
191
57
            return(NULL);
192
57
        }
193
851k
        memcpy(ret->mem, mem, size);
194
851k
        ret->mem[size] = 0;
195
851k
    }
196
197
859k
    ret->use = size;
198
859k
    ret->size = size;
199
859k
    ret->maxSize = SIZE_MAX - 1;
200
859k
    ret->content = ret->mem;
201
202
859k
    UPDATE_COMPAT(ret);
203
859k
    return(ret);
204
859k
}
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
1.03M
xmlBufDetach(xmlBufPtr buf) {
218
1.03M
    xmlChar *ret;
219
220
1.03M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
221
75
        return(NULL);
222
223
1.03M
    if (buf->content != buf->mem) {
224
0
        ret = xmlStrndup(buf->content, buf->use);
225
0
        xmlFree(buf->mem);
226
1.03M
    } else {
227
1.03M
        ret = buf->mem;
228
1.03M
    }
229
230
1.03M
    buf->content = NULL;
231
1.03M
    buf->mem = NULL;
232
1.03M
    buf->size = 0;
233
1.03M
    buf->use = 0;
234
235
1.03M
    UPDATE_COMPAT(buf);
236
1.03M
    return ret;
237
1.03M
}
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
2.08M
xmlBufFree(xmlBufPtr buf) {
248
2.08M
    if (buf == NULL)
249
0
  return;
250
251
2.08M
    if (!BUF_STATIC(buf))
252
2.07M
        xmlFree(buf->mem);
253
2.08M
    xmlFree(buf);
254
2.08M
}
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
113M
xmlBufShrink(xmlBufPtr buf, size_t len) {
294
113M
    if ((buf == NULL) || (BUF_ERROR(buf)))
295
1.30k
        return(0);
296
113M
    if (len == 0)
297
45.2M
        return(0);
298
68.1M
    CHECK_COMPAT(buf)
299
300
68.1M
    if (len > buf->use)
301
0
        return(0);
302
303
68.1M
    buf->use -= len;
304
68.1M
    buf->content += len;
305
68.1M
    buf->size -= len;
306
307
68.1M
    UPDATE_COMPAT(buf)
308
68.1M
    return(len);
309
68.1M
}
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
983k
xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
322
983k
    size_t size;
323
983k
    size_t start;
324
983k
    xmlChar *newbuf;
325
326
    /*
327
     * If there's enough space at the start of the buffer,
328
     * move the contents.
329
     */
330
983k
    start = buf->content - buf->mem;
331
983k
    if (len <= start + buf->size - buf->use) {
332
41.7k
        memmove(buf->mem, buf->content, buf->use + 1);
333
41.7k
        buf->size += start;
334
41.7k
        buf->content = buf->mem;
335
41.7k
        return(0);
336
41.7k
    }
337
338
941k
    if (len > buf->maxSize - buf->use) {
339
0
        xmlBufOverflowError(buf);
340
0
        return(-1);
341
0
    }
342
343
941k
    if (buf->size > (size_t) len) {
344
660k
        if (buf->size <= buf->maxSize / 2)
345
660k
            size = buf->size * 2;
346
0
        else
347
0
            size = buf->maxSize;
348
660k
    } else {
349
280k
        size = buf->use + len;
350
280k
        if (size <= buf->maxSize - 100)
351
280k
            size += 100;
352
280k
    }
353
354
941k
    if (buf->content == buf->mem) {
355
928k
        newbuf = xmlRealloc(buf->mem, size + 1);
356
928k
        if (newbuf == NULL) {
357
88
            xmlBufMemoryError(buf);
358
88
            return(-1);
359
88
        }
360
928k
    } else {
361
13.1k
        newbuf = xmlMalloc(size + 1);
362
13.1k
        if (newbuf == NULL) {
363
8
            xmlBufMemoryError(buf);
364
8
            return(-1);
365
8
        }
366
13.1k
        if (buf->content != NULL)
367
13.1k
            memcpy(newbuf, buf->content, buf->use + 1);
368
13.1k
        xmlFree(buf->mem);
369
13.1k
    }
370
371
941k
    buf->mem = newbuf;
372
941k
    buf->content = newbuf;
373
941k
    buf->size = size;
374
375
941k
    return(0);
376
941k
}
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
52.0M
xmlBufGrow(xmlBufPtr buf, size_t len) {
390
52.0M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
391
0
        return(-1);
392
52.0M
    CHECK_COMPAT(buf)
393
394
52.0M
    if (len <= buf->size - buf->use)
395
51.9M
        return(0);
396
397
48.4k
    if (xmlBufGrowInternal(buf, len) < 0)
398
15
        return(-1);
399
400
48.4k
    UPDATE_COMPAT(buf)
401
48.4k
    return(0);
402
48.4k
}
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
96.3M
{
416
96.3M
    if ((!buf) || (BUF_ERROR(buf)))
417
13
        return NULL;
418
419
96.3M
    return(buf->content);
420
96.3M
}
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
100M
{
434
100M
    if ((!buf) || (BUF_ERROR(buf)))
435
0
        return NULL;
436
100M
    CHECK_COMPAT(buf)
437
438
100M
    return(&buf->content[buf->use]);
439
100M
}
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
100M
xmlBufAddLen(xmlBufPtr buf, size_t len) {
454
100M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
455
0
        return(-1);
456
100M
    CHECK_COMPAT(buf)
457
100M
    if (len > buf->size - buf->use)
458
0
        return(-1);
459
100M
    buf->use += len;
460
100M
    buf->content[buf->use] = 0;
461
100M
    UPDATE_COMPAT(buf)
462
100M
    return(0);
463
100M
}
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
106M
{
477
106M
    if ((!buf) || (BUF_ERROR(buf)))
478
13
        return 0;
479
106M
    CHECK_COMPAT(buf)
480
481
106M
    return(buf->use);
482
106M
}
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
96.3M
{
499
96.3M
    if ((!buf) || (BUF_ERROR(buf)))
500
0
        return 0;
501
96.3M
    CHECK_COMPAT(buf)
502
503
96.3M
    return(buf->size - buf->use);
504
96.3M
}
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
0
{
517
0
    if ((!buf) || (BUF_ERROR(buf)))
518
0
        return(-1);
519
0
    CHECK_COMPAT(buf)
520
521
0
    return(buf->use == 0);
522
0
}
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
123M
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, size_t len) {
537
123M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
538
1.03k
        return(-1);
539
123M
    if (len == 0)
540
172k
        return(0);
541
123M
    if (str == NULL)
542
0
  return(-1);
543
123M
    CHECK_COMPAT(buf)
544
545
123M
    if (len > buf->size - buf->use) {
546
934k
        if (xmlBufGrowInternal(buf, len) < 0)
547
81
            return(-1);
548
934k
    }
549
550
123M
    memmove(&buf->content[buf->use], str, len);
551
123M
    buf->use += len;
552
123M
    buf->content[buf->use] = 0;
553
554
123M
    UPDATE_COMPAT(buf)
555
123M
    return(0);
556
123M
}
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
7.44M
xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
570
7.44M
    if (str == NULL)
571
0
        return(0);
572
7.44M
    return(xmlBufAdd(buf, str, strlen((const char *) str)));
573
7.44M
}
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
 * @ret: old buffer
626
 *
627
 * Function to be called once internal processing had been done to
628
 * update back the buffer provided by the user. This can lead to
629
 * a failure in case the size accumulated in the xmlBuf is larger
630
 * than what an xmlBuffer can support on 64 bits (INT_MAX)
631
 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
632
 *
633
 * Returns 0 on success, -1 on error.
634
 */
635
int
636
0
xmlBufBackToBuffer(xmlBufPtr buf, xmlBufferPtr ret) {
637
0
    if ((buf == NULL) || (ret == NULL))
638
0
        return(-1);
639
640
0
    if ((BUF_ERROR(buf)) || (BUF_STATIC(buf)) ||
641
0
        (buf->use >= INT_MAX)) {
642
0
        xmlBufFree(buf);
643
0
        ret->content = NULL;
644
0
        ret->contentIO = NULL;
645
0
        ret->use = 0;
646
0
        ret->size = 0;
647
0
        return(-1);
648
0
    }
649
650
0
    ret->use = buf->use;
651
0
    if (buf->size >= INT_MAX) {
652
        /* Keep the buffer but provide a truncated size value. */
653
0
        ret->size = INT_MAX;
654
0
    } else {
655
0
        ret->size = buf->size + 1;
656
0
    }
657
0
    ret->alloc = XML_BUFFER_ALLOC_IO;
658
0
    ret->content = buf->content;
659
0
    ret->contentIO = buf->mem;
660
0
    xmlFree(buf);
661
0
    return(0);
662
0
}
663
664
/**
665
 * xmlBufResetInput:
666
 * @buf: an xmlBufPtr
667
 * @input: an xmlParserInputPtr
668
 *
669
 * Update the input to use the current set of pointers from the buffer.
670
 *
671
 * Returns -1 in case of error, 0 otherwise
672
 */
673
int
674
1.06M
xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
675
1.06M
    return(xmlBufUpdateInput(buf, input, 0));
676
1.06M
}
677
678
/**
679
 * xmlBufUpdateInput:
680
 * @buf: an xmlBufPtr
681
 * @input: an xmlParserInputPtr
682
 * @pos: the cur value relative to the beginning of the buffer
683
 *
684
 * Update the input to use the base and cur relative to the buffer
685
 * after a possible reallocation of its content
686
 *
687
 * Returns -1 in case of error, 0 otherwise
688
 */
689
int
690
30.2M
xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
691
30.2M
    if ((buf == NULL) || (input == NULL))
692
0
        return(-1);
693
30.2M
    CHECK_COMPAT(buf)
694
30.2M
    input->base = buf->content;
695
30.2M
    input->cur = input->base + pos;
696
30.2M
    input->end = &buf->content[buf->use];
697
30.2M
    return(0);
698
30.2M
}
699
700
/************************************************************************
701
 *                  *
702
 *      Old buffer implementation     *
703
 *                  *
704
 ************************************************************************/
705
706
/**
707
 * xmlSetBufferAllocationScheme:
708
 * @scheme:  allocation method to use
709
 *
710
 * DEPRECATED: Use xmlBufferSetAllocationScheme.
711
 *
712
 * Set the buffer allocation method.  Types are
713
 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
714
 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
715
 *                             improves performance
716
 */
717
void
718
0
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme ATTRIBUTE_UNUSED) {
719
0
}
720
721
/**
722
 * xmlGetBufferAllocationScheme:
723
 *
724
 * DEPRECATED: Use xmlBufferSetAllocationScheme.
725
 *
726
 * Types are
727
 * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
728
 * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed,
729
 *                             improves performance
730
 * XML_BUFFER_ALLOC_HYBRID - use exact sizes on small strings to keep memory usage tight
731
 *                            in normal usage, and doubleit on large strings to avoid
732
 *                            pathological performance.
733
 *
734
 * Returns the current allocation scheme
735
 */
736
xmlBufferAllocationScheme
737
0
xmlGetBufferAllocationScheme(void) {
738
0
    return(XML_BUFFER_ALLOC_EXACT);
739
0
}
740
741
/**
742
 * xmlBufferCreate:
743
 *
744
 * routine to create an XML buffer.
745
 * returns the new structure.
746
 */
747
xmlBufferPtr
748
109k
xmlBufferCreate(void) {
749
109k
    xmlBufferPtr ret;
750
751
109k
    ret = xmlMalloc(sizeof(*ret));
752
109k
    if (ret == NULL)
753
940
        return(NULL);
754
755
108k
    ret->use = 0;
756
108k
    ret->size = 256;
757
108k
    ret->alloc = XML_BUFFER_ALLOC_IO;
758
108k
    ret->contentIO = xmlMalloc(ret->size);
759
108k
    if (ret->contentIO == NULL) {
760
20
  xmlFree(ret);
761
20
        return(NULL);
762
20
    }
763
108k
    ret->content = ret->contentIO;
764
108k
    ret->content[0] = 0;
765
766
108k
    return(ret);
767
108k
}
768
769
/**
770
 * xmlBufferCreateSize:
771
 * @size: initial size of buffer
772
 *
773
 * routine to create an XML buffer.
774
 * returns the new structure.
775
 */
776
xmlBufferPtr
777
278
xmlBufferCreateSize(size_t size) {
778
278
    xmlBufferPtr ret;
779
780
278
    if (size >= INT_MAX)
781
0
        return(NULL);
782
783
278
    ret = xmlMalloc(sizeof(*ret));
784
278
    if (ret == NULL)
785
2
        return(NULL);
786
787
276
    ret->use = 0;
788
276
    ret->alloc = XML_BUFFER_ALLOC_IO;
789
276
    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
790
791
276
    if (ret->size) {
792
276
        ret->contentIO = xmlMalloc(ret->size);
793
276
        if (ret->contentIO == NULL) {
794
1
            xmlFree(ret);
795
1
            return(NULL);
796
1
        }
797
275
        ret->content = ret->contentIO;
798
275
        ret->content[0] = 0;
799
275
    } else {
800
0
        ret->contentIO = NULL;
801
0
  ret->content = NULL;
802
0
    }
803
804
275
    return(ret);
805
276
}
806
807
/**
808
 * xmlBufferDetach:
809
 * @buf:  the buffer
810
 *
811
 * Remove the string contained in a buffer and gie it back to the
812
 * caller. The buffer is reset to an empty content.
813
 * This doesn't work with immutable buffers as they can't be reset.
814
 *
815
 * Returns the previous string contained by the buffer.
816
 */
817
xmlChar *
818
275
xmlBufferDetach(xmlBufferPtr buf) {
819
275
    xmlChar *ret;
820
821
275
    if (buf == NULL)
822
0
        return(NULL);
823
824
275
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
825
275
        (buf->content != buf->contentIO)) {
826
0
        ret = xmlStrndup(buf->content, buf->use);
827
0
        xmlFree(buf->contentIO);
828
275
    } else {
829
275
        ret = buf->content;
830
275
    }
831
832
275
    buf->contentIO = NULL;
833
275
    buf->content = NULL;
834
275
    buf->size = 0;
835
275
    buf->use = 0;
836
837
275
    return ret;
838
275
}
839
840
/**
841
 * xmlBufferCreateStatic:
842
 * @mem: the memory area
843
 * @size:  the size in byte
844
 *
845
 * Returns an XML buffer initialized with bytes.
846
 */
847
xmlBufferPtr
848
0
xmlBufferCreateStatic(void *mem, size_t size) {
849
0
    xmlBufferPtr buf = xmlBufferCreateSize(size);
850
851
0
    xmlBufferAdd(buf, mem, size);
852
0
    return(buf);
853
0
}
854
855
/**
856
 * xmlBufferSetAllocationScheme:
857
 * @buf:  the buffer to tune
858
 * @scheme:  allocation scheme to use
859
 *
860
 * Sets the allocation scheme for this buffer.
861
 *
862
 * For libxml2 before 2.14, it is recommended to set this to
863
 * XML_BUFFER_ALLOC_DOUBLE_IT. Has no effect on 2.14 or later.
864
 */
865
void
866
xmlBufferSetAllocationScheme(xmlBufferPtr buf ATTRIBUTE_UNUSED,
867
12.2k
                             xmlBufferAllocationScheme scheme ATTRIBUTE_UNUSED) {
868
12.2k
}
869
870
/**
871
 * xmlBufferFree:
872
 * @buf:  the buffer to free
873
 *
874
 * Frees an XML buffer. It frees both the content and the structure which
875
 * encapsulate it.
876
 */
877
void
878
109k
xmlBufferFree(xmlBufferPtr buf) {
879
109k
    if (buf == NULL)
880
0
  return;
881
882
109k
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
883
109k
        xmlFree(buf->contentIO);
884
0
    else
885
0
        xmlFree(buf->content);
886
887
109k
    xmlFree(buf);
888
109k
}
889
890
/**
891
 * xmlBufferEmpty:
892
 * @buf:  the buffer
893
 *
894
 * empty a buffer.
895
 */
896
void
897
0
xmlBufferEmpty(xmlBufferPtr buf) {
898
0
    if (buf == NULL)
899
0
        return;
900
0
    if (buf->content == NULL)
901
0
        return;
902
903
0
    buf->use = 0;
904
905
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
906
0
  buf->size += buf->content - buf->contentIO;
907
0
        buf->content = buf->contentIO;
908
0
        buf->content[0] = 0;
909
0
    } else {
910
0
        buf->content[0] = 0;
911
0
    }
912
0
}
913
914
/**
915
 * xmlBufferShrink:
916
 * @buf:  the buffer to dump
917
 * @len:  the number of xmlChar to remove
918
 *
919
 * DEPRECATED: Don't use.
920
 *
921
 * Remove the beginning of an XML buffer.
922
 *
923
 * Returns the number of #xmlChar removed, or -1 in case of failure.
924
 */
925
int
926
0
xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
927
0
    if (buf == NULL)
928
0
        return(-1);
929
0
    if (len == 0)
930
0
        return(0);
931
0
    if (len > buf->use)
932
0
        return(-1);
933
934
0
    buf->use -= len;
935
936
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
937
0
        buf->content += len;
938
0
  buf->size -= len;
939
0
    } else {
940
0
  memmove(buf->content, &buf->content[len], buf->use + 1);
941
0
    }
942
943
0
    return(len);
944
0
}
945
946
/**
947
 * xmlBufferGrow:
948
 * @buf:  the buffer
949
 * @len:  the minimum free size to allocate
950
 *
951
 * DEPRECATED: Don't use.
952
 *
953
 * Grow the available space of an XML buffer.
954
 *
955
 * Returns the new available space or -1 in case of error
956
 */
957
int
958
23.4k
xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
959
23.4k
    unsigned int size;
960
23.4k
    xmlChar *newbuf;
961
962
23.4k
    if (buf == NULL)
963
0
        return(-1);
964
965
23.4k
    if (len < buf->size - buf->use)
966
0
        return(0);
967
23.4k
    if (len >= INT_MAX - buf->use)
968
0
        return(-1);
969
970
23.4k
    if (buf->size > (size_t) len) {
971
22.6k
        if (buf->size <= INT_MAX / 2)
972
22.6k
            size = buf->size * 2;
973
0
        else
974
0
            size = INT_MAX;
975
22.6k
    } else {
976
796
        size = buf->use + len + 1;
977
796
        if (size <= INT_MAX - 100)
978
796
            size += 100;
979
796
    }
980
981
23.4k
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
982
23.4k
        (buf->content != buf->contentIO)) {
983
0
        newbuf = xmlMalloc(size);
984
0
        if (newbuf == NULL)
985
0
            return(-1);
986
0
        if (buf->content != NULL)
987
0
            memcpy(newbuf, buf->content, buf->use + 1);
988
0
        xmlFree(buf->contentIO);
989
23.4k
    } else {
990
23.4k
        newbuf = xmlRealloc(buf->content, size);
991
23.4k
        if (newbuf == NULL)
992
16.9k
            return(-1);
993
23.4k
    }
994
995
6.52k
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
996
6.52k
        buf->contentIO = newbuf;
997
6.52k
    buf->content = newbuf;
998
6.52k
    buf->size = size;
999
1000
6.52k
    return(buf->size - buf->use - 1);
1001
23.4k
}
1002
1003
/**
1004
 * xmlBufferDump:
1005
 * @file:  the file output
1006
 * @buf:  the buffer to dump
1007
 *
1008
 * Dumps an XML buffer to  a FILE *.
1009
 * Returns the number of #xmlChar written
1010
 */
1011
int
1012
0
xmlBufferDump(FILE *file, xmlBufferPtr buf) {
1013
0
    size_t ret;
1014
1015
0
    if (buf == NULL)
1016
0
  return(0);
1017
0
    if (buf->content == NULL)
1018
0
  return(0);
1019
0
    if (file == NULL)
1020
0
  file = stdout;
1021
0
    ret = fwrite(buf->content, 1, buf->use, file);
1022
0
    return(ret > INT_MAX ? INT_MAX : ret);
1023
0
}
1024
1025
/**
1026
 * xmlBufferContent:
1027
 * @buf:  the buffer
1028
 *
1029
 * Function to extract the content of a buffer
1030
 *
1031
 * Returns the internal content
1032
 */
1033
1034
const xmlChar *
1035
xmlBufferContent(const xmlBuffer *buf)
1036
108k
{
1037
108k
    if(!buf)
1038
0
        return NULL;
1039
1040
108k
    return buf->content;
1041
108k
}
1042
1043
/**
1044
 * xmlBufferLength:
1045
 * @buf:  the buffer
1046
 *
1047
 * Function to get the length of a buffer
1048
 *
1049
 * Returns the length of data in the internal content
1050
 */
1051
1052
int
1053
xmlBufferLength(const xmlBuffer *buf)
1054
11.9k
{
1055
11.9k
    if(!buf)
1056
0
        return 0;
1057
1058
11.9k
    return buf->use;
1059
11.9k
}
1060
1061
/**
1062
 * xmlBufferResize:
1063
 * @buf:  the buffer to resize
1064
 * @size:  the desired size
1065
 *
1066
 * DEPRECATED: Don't use.
1067
1068
 * Resize a buffer to accommodate minimum size of @size.
1069
 *
1070
 * Returns  0 in case of problems, 1 otherwise
1071
 */
1072
int
1073
xmlBufferResize(xmlBufferPtr buf, unsigned int size)
1074
0
{
1075
0
    int res;
1076
1077
0
    if (buf == NULL)
1078
0
        return(0);
1079
0
    if (size < buf->size)
1080
0
        return(1);
1081
0
    res = xmlBufferGrow(buf, size - buf->use);
1082
1083
0
    return(res < 0 ? 0 : 1);
1084
0
}
1085
1086
/**
1087
 * xmlBufferAdd:
1088
 * @buf:  the buffer to dump
1089
 * @str:  the #xmlChar string
1090
 * @len:  the number of #xmlChar to add
1091
 *
1092
 * Add a string range to an XML buffer. if len == -1, the length of
1093
 * str is recomputed.
1094
 *
1095
 * Returns a xmlParserErrors code.
1096
 */
1097
int
1098
2.20M
xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
1099
2.20M
    if ((buf == NULL) || (str == NULL))
1100
0
  return(XML_ERR_ARGUMENT);
1101
2.20M
    if (len < 0)
1102
405k
        len = xmlStrlen(str);
1103
2.20M
    if (len == 0)
1104
1.10k
        return(XML_ERR_OK);
1105
1106
    /* Note that both buf->size and buf->use can be zero here. */
1107
2.20M
    if ((unsigned) len >= buf->size - buf->use) {
1108
23.4k
        if (xmlBufferGrow(buf, len) < 0)
1109
16.9k
            return(XML_ERR_NO_MEMORY);
1110
23.4k
    }
1111
1112
2.19M
    memmove(&buf->content[buf->use], str, len);
1113
2.19M
    buf->use += len;
1114
2.19M
    buf->content[buf->use] = 0;
1115
2.19M
    return(XML_ERR_OK);
1116
2.20M
}
1117
1118
/**
1119
 * xmlBufferAddHead:
1120
 * @buf:  the buffer
1121
 * @str:  the #xmlChar string
1122
 * @len:  the number of #xmlChar to add
1123
 *
1124
 * Add a string range to the beginning of an XML buffer.
1125
 * if len == -1, the length of @str is recomputed.
1126
 *
1127
 * Returns a xmlParserErrors code.
1128
 */
1129
int
1130
0
xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
1131
0
    unsigned start = 0;
1132
1133
0
    if ((buf == NULL) || (str == NULL))
1134
0
  return(XML_ERR_ARGUMENT);
1135
0
    if (len < 0)
1136
0
        len = xmlStrlen(str);
1137
0
    if (len == 0)
1138
0
        return(XML_ERR_OK);
1139
1140
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
1141
0
        start = buf->content - buf->contentIO;
1142
1143
        /*
1144
         * We can add it in the space previously shrunk
1145
         */
1146
0
        if ((unsigned) len <= start) {
1147
0
            buf->content -= len;
1148
0
            memmove(&buf->content[0], str, len);
1149
0
            buf->use += len;
1150
0
            buf->size += len;
1151
0
            return(0);
1152
0
        }
1153
0
        if ((unsigned) len < buf->size + start - buf->use) {
1154
0
            memmove(&buf->contentIO[len], buf->content, buf->use + 1);
1155
0
            memmove(buf->contentIO, str, len);
1156
0
            buf->content = buf->contentIO;
1157
0
            buf->use += len;
1158
0
            buf->size += start;
1159
0
            return(0);
1160
0
        }
1161
0
    }
1162
1163
0
    if ((unsigned) len >= buf->size - buf->use) {
1164
0
        if (xmlBufferGrow(buf, len) < 0)
1165
0
            return(-1);
1166
0
    }
1167
1168
0
    memmove(&buf->content[len], buf->content, buf->use + 1);
1169
0
    memmove(buf->content, str, len);
1170
0
    buf->use += len;
1171
0
    return (0);
1172
0
}
1173
1174
/**
1175
 * xmlBufferCat:
1176
 * @buf:  the buffer to add to
1177
 * @str:  the #xmlChar string
1178
 *
1179
 * Append a zero terminated string to an XML buffer.
1180
 *
1181
 * Returns 0 successful, a positive error code number otherwise
1182
 *         and -1 in case of internal or API error.
1183
 */
1184
int
1185
91.5k
xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
1186
91.5k
    return(xmlBufferAdd(buf, str, -1));
1187
91.5k
}
1188
1189
/**
1190
 * xmlBufferCCat:
1191
 * @buf:  the buffer to dump
1192
 * @str:  the C char string
1193
 *
1194
 * Append a zero terminated C string to an XML buffer.
1195
 *
1196
 * Returns 0 successful, a positive error code number otherwise
1197
 *         and -1 in case of internal or API error.
1198
 */
1199
int
1200
314k
xmlBufferCCat(xmlBufferPtr buf, const char *str) {
1201
314k
    return(xmlBufferAdd(buf, (const xmlChar *) str, -1));
1202
314k
}
1203
1204
/**
1205
 * xmlBufferWriteCHAR:
1206
 * @buf:  the XML buffer
1207
 * @string:  the string to add
1208
 *
1209
 * routine which manages and grows an output buffer. This one adds
1210
 * xmlChars at the end of the buffer.
1211
 */
1212
void
1213
0
xmlBufferWriteCHAR(xmlBufferPtr buf, const xmlChar *string) {
1214
0
    xmlBufferAdd(buf, string, -1);
1215
0
}
1216
1217
/**
1218
 * xmlBufferWriteChar:
1219
 * @buf:  the XML buffer output
1220
 * @string:  the string to add
1221
 *
1222
 * routine which manage and grows an output buffer. This one add
1223
 * C chars at the end of the array.
1224
 */
1225
void
1226
0
xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
1227
0
    xmlBufferAdd(buf, (const xmlChar *) string, -1);
1228
0
}
1229
1230
1231
/**
1232
 * xmlBufferWriteQuotedString:
1233
 * @buf:  the XML buffer output
1234
 * @string:  the string to add
1235
 *
1236
 * routine which manage and grows an output buffer. This one writes
1237
 * a quoted or double quoted #xmlChar string, checking first if it holds
1238
 * quote or double-quotes internally
1239
 */
1240
void
1241
0
xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
1242
0
    const xmlChar *cur, *base;
1243
0
    if (buf == NULL)
1244
0
        return;
1245
0
    if (xmlStrchr(string, '\"')) {
1246
0
        if (xmlStrchr(string, '\'')) {
1247
0
      xmlBufferCCat(buf, "\"");
1248
0
            base = cur = string;
1249
0
            while(*cur != 0){
1250
0
                if(*cur == '"'){
1251
0
                    if (base != cur)
1252
0
                        xmlBufferAdd(buf, base, cur - base);
1253
0
                    xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
1254
0
                    cur++;
1255
0
                    base = cur;
1256
0
                }
1257
0
                else {
1258
0
                    cur++;
1259
0
                }
1260
0
            }
1261
0
            if (base != cur)
1262
0
                xmlBufferAdd(buf, base, cur - base);
1263
0
      xmlBufferCCat(buf, "\"");
1264
0
  }
1265
0
        else{
1266
0
      xmlBufferCCat(buf, "\'");
1267
0
            xmlBufferCat(buf, string);
1268
0
      xmlBufferCCat(buf, "\'");
1269
0
        }
1270
0
    } else {
1271
0
        xmlBufferCCat(buf, "\"");
1272
0
        xmlBufferCat(buf, string);
1273
0
        xmlBufferCCat(buf, "\"");
1274
0
    }
1275
0
}
1276