Coverage Report

Created: 2025-07-11 06:13

/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 xmlBuf opaque structure and
8
 * xmlBuf...() counterparts to the old xmlBuf...() functions
9
 *
10
 * See Copyright for the status of this software.
11
 *
12
 * Author: Daniel Veillard
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
1.80G
#define BUF_FLAG_OOM        (1u << 0)
31
1.80G
#define BUF_FLAG_OVERFLOW   (1u << 1)
32
570M
#define BUF_FLAG_STATIC     (1u << 2)
33
34
1.80G
#define BUF_ERROR(buf) ((buf)->flags & (BUF_FLAG_OOM | BUF_FLAG_OVERFLOW))
35
570M
#define BUF_STATIC(buf) ((buf)->flags & BUF_FLAG_STATIC)
36
37
/**
38
 * A buffer structure. The base of the structure is somehow compatible
39
 * with struct _xmlBuffer to limit risks on application which accessed
40
 * directly the input->buf->buffer structures.
41
 */
42
43
struct _xmlBuf {
44
    xmlChar *content;   /* The buffer content UTF8 */
45
    xmlChar *mem;   /* Start of the allocation */
46
    size_t use;           /* The buffer size used */
47
    size_t size;    /* The buffer size, excluding terminating 0 */
48
    size_t maxSize;             /* The maximum buffer size */
49
    unsigned flags;             /* flags */
50
};
51
52
/**
53
 * Handle an out of memory condition
54
 * To be improved...
55
 *
56
 * @param buf  the buffer
57
 */
58
static void
59
xmlBufMemoryError(xmlBufPtr buf)
60
83
{
61
83
    if (!BUF_ERROR(buf))
62
83
        buf->flags |= BUF_FLAG_OOM;
63
83
}
64
65
/**
66
 * Handle a buffer overflow error
67
 * To be improved...
68
 *
69
 * @param buf  the buffer
70
 */
71
static void
72
xmlBufOverflowError(xmlBufPtr buf)
73
0
{
74
0
    if (!BUF_ERROR(buf))
75
0
        buf->flags |= BUF_FLAG_OVERFLOW;
76
0
}
77
78
/**
79
 * Create a buffer.
80
 *
81
 * @param size  initial buffer size
82
 * @returns  the new structure
83
 */
84
xmlBuf *
85
1.34M
xmlBufCreate(size_t size) {
86
1.34M
    xmlBufPtr ret;
87
88
1.34M
    if (size == SIZE_MAX)
89
0
        return(NULL);
90
91
1.34M
    ret = xmlMalloc(sizeof(*ret));
92
1.34M
    if (ret == NULL)
93
4.63k
        return(NULL);
94
95
1.34M
    ret->use = 0;
96
1.34M
    ret->flags = 0;
97
1.34M
    ret->size = size;
98
1.34M
    ret->maxSize = SIZE_MAX - 1;
99
100
1.34M
    ret->mem = xmlMalloc(ret->size + 1);
101
1.34M
    if (ret->mem == NULL) {
102
131
        xmlFree(ret);
103
131
        return(NULL);
104
131
    }
105
1.34M
    ret->content = ret->mem;
106
1.34M
    ret->content[0] = 0;
107
108
1.34M
    return(ret);
109
1.34M
}
110
111
/**
112
 * Create a buffer initialized with memory.
113
 *
114
 * If `isStatic` is set, uses the memory area directly as backing store.
115
 * The memory must be zero-terminated and not be modified for the
116
 * lifetime of the buffer. A static buffer can't be grown, modified or
117
 * detached, but it can be shrunk.
118
 *
119
 * @param mem  a memory area
120
 * @param size  size of the buffer excluding terminator
121
 * @param isStatic  whether the memory area is static
122
 * @returns  a new buffer.
123
 */
124
xmlBuf *
125
831k
xmlBufCreateMem(const xmlChar *mem, size_t size, int isStatic) {
126
831k
    xmlBufPtr ret;
127
128
831k
    if (mem == NULL)
129
0
        return(NULL);
130
131
831k
    ret = xmlMalloc(sizeof(*ret));
132
831k
    if (ret == NULL)
133
51
        return(NULL);
134
135
831k
    if (isStatic) {
136
        /* Check that memory is zero-terminated */
137
10.1k
        if (mem[size] != 0) {
138
0
            xmlFree(ret);
139
0
            return(NULL);
140
0
        }
141
10.1k
        ret->flags = BUF_FLAG_STATIC;
142
10.1k
        ret->mem = (xmlChar *) mem;
143
821k
    } else {
144
821k
        ret->flags = 0;
145
821k
        ret->mem = xmlMalloc(size + 1);
146
821k
        if (ret->mem == NULL) {
147
59
            xmlFree(ret);
148
59
            return(NULL);
149
59
        }
150
821k
        memcpy(ret->mem, mem, size);
151
821k
        ret->mem[size] = 0;
152
821k
    }
153
154
831k
    ret->use = size;
155
831k
    ret->size = size;
156
831k
    ret->maxSize = SIZE_MAX - 1;
157
831k
    ret->content = ret->mem;
158
159
831k
    return(ret);
160
831k
}
161
162
/**
163
 * Extract buffer content.
164
 *
165
 * Return the content of the buffer as an `xmlChar` string,
166
 * clearing the buffer.
167
 *
168
 * This doesn't work with static buffers as they can't be reset.
169
 *
170
 * @param buf  the buffer
171
 * @returns  the buffer content
172
 */
173
xmlChar *
174
1.14M
xmlBufDetach(xmlBuf *buf) {
175
1.14M
    xmlChar *ret;
176
177
1.14M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
178
53
        return(NULL);
179
180
1.14M
    if (buf->content != buf->mem) {
181
0
        ret = xmlStrndup(buf->content, buf->use);
182
0
        xmlFree(buf->mem);
183
1.14M
    } else {
184
1.14M
        ret = buf->mem;
185
1.14M
    }
186
187
1.14M
    buf->content = NULL;
188
1.14M
    buf->mem = NULL;
189
1.14M
    buf->size = 0;
190
1.14M
    buf->use = 0;
191
192
1.14M
    return ret;
193
1.14M
}
194
195
/**
196
 * Free a buffer.
197
 *
198
 * @param buf  the buffer to free
199
 */
200
void
201
2.17M
xmlBufFree(xmlBuf *buf) {
202
2.17M
    if (buf == NULL)
203
0
  return;
204
205
2.17M
    if (!BUF_STATIC(buf))
206
2.16M
        xmlFree(buf->mem);
207
2.17M
    xmlFree(buf);
208
2.17M
}
209
210
/**
211
 * Empty a buffer.
212
 *
213
 * @param buf  the buffer
214
 */
215
void
216
0
xmlBufEmpty(xmlBuf *buf) {
217
0
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
218
0
        return;
219
0
    if (buf->mem == NULL)
220
0
        return;
221
222
0
    buf->use = 0;
223
0
    buf->size += buf->content - buf->mem;
224
0
    buf->content = buf->mem;
225
0
    buf->content[0] = 0;
226
0
}
227
228
/**
229
 * Discard bytes at the start of a buffer.
230
 *
231
 * NOTE that the return value differs from #xmlBufferShrink
232
 * as it will return 0 on error instead of -1 due to size_t being
233
 * used as the return type.
234
 *
235
 * @deprecated Internal function, don't use.
236
 *
237
 * @param buf  the buffer
238
 * @param len  the number of bytes to remove
239
 * @returns  the number of bytes removed or 0 in case of failure
240
 */
241
size_t
242
258M
xmlBufShrink(xmlBuf *buf, size_t len) {
243
258M
    if ((buf == NULL) || (BUF_ERROR(buf)))
244
1.81k
        return(0);
245
258M
    if (len == 0)
246
112M
        return(0);
247
248
146M
    if (len > buf->use)
249
0
        return(0);
250
251
146M
    buf->use -= len;
252
146M
    buf->content += len;
253
146M
    buf->size -= len;
254
255
146M
    return(len);
256
146M
}
257
258
/**
259
 * Grow a buffer.
260
 *
261
 * Increase the capacity of a buffer. `len` is the amount of
262
 * free space required after the current end of the buffer.
263
 *
264
 * Assumes `len > buf->size - buf->use`.
265
 *
266
 * @param buf  the buffer
267
 * @param len  number of extra bytes to allocate
268
 * @returns  0 on success, -1 in case of error
269
 */
270
static int
271
1.37M
xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
272
1.37M
    size_t size;
273
1.37M
    size_t start;
274
1.37M
    xmlChar *newbuf;
275
276
    /*
277
     * If there's enough space at the start of the buffer,
278
     * move the contents.
279
     */
280
1.37M
    start = buf->content - buf->mem;
281
1.37M
    if (len <= start + buf->size - buf->use) {
282
107k
        memmove(buf->mem, buf->content, buf->use + 1);
283
107k
        buf->size += start;
284
107k
        buf->content = buf->mem;
285
107k
        return(0);
286
107k
    }
287
288
1.27M
    if (len > buf->maxSize - buf->use) {
289
0
        xmlBufOverflowError(buf);
290
0
        return(-1);
291
0
    }
292
293
1.27M
    if (buf->size > (size_t) len) {
294
825k
        if (buf->size <= buf->maxSize / 2)
295
825k
            size = buf->size * 2;
296
0
        else
297
0
            size = buf->maxSize;
298
825k
    } else {
299
444k
        size = buf->use + len;
300
444k
        if (size <= buf->maxSize - 100)
301
444k
            size += 100;
302
444k
    }
303
304
1.27M
    if (buf->content == buf->mem) {
305
1.25M
        newbuf = xmlRealloc(buf->mem, size + 1);
306
1.25M
        if (newbuf == NULL) {
307
70
            xmlBufMemoryError(buf);
308
70
            return(-1);
309
70
        }
310
1.25M
    } else {
311
19.2k
        newbuf = xmlMalloc(size + 1);
312
19.2k
        if (newbuf == NULL) {
313
13
            xmlBufMemoryError(buf);
314
13
            return(-1);
315
13
        }
316
19.2k
        if (buf->content != NULL)
317
19.2k
            memcpy(newbuf, buf->content, buf->use + 1);
318
19.2k
        xmlFree(buf->mem);
319
19.2k
    }
320
321
1.27M
    buf->mem = newbuf;
322
1.27M
    buf->content = newbuf;
323
1.27M
    buf->size = size;
324
325
1.27M
    return(0);
326
1.27M
}
327
328
/**
329
 * Grow a buffer.
330
 *
331
 * Increase the capacity of a buffer. `len` is the amount of
332
 * free space required after the current end of the buffer.
333
 *
334
 * @param buf  the buffer
335
 * @param len  number of extra bytes to allocate
336
 * @returns  0 on success, -1 in case of error
337
 */
338
int
339
122M
xmlBufGrow(xmlBuf *buf, size_t len) {
340
122M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
341
0
        return(-1);
342
343
122M
    if (len <= buf->size - buf->use)
344
122M
        return(0);
345
346
62.8k
    if (xmlBufGrowInternal(buf, len) < 0)
347
18
        return(-1);
348
349
62.8k
    return(0);
350
62.8k
}
351
352
/**
353
 * Get pointer into buffer content.
354
 *
355
 * @param buf  the buffer
356
 * @returns  the internal content or NULL in case of error
357
 */
358
xmlChar *
359
xmlBufContent(const xmlBuf *buf)
360
237M
{
361
237M
    if ((!buf) || (BUF_ERROR(buf)))
362
13
        return NULL;
363
364
237M
    return(buf->content);
365
237M
}
366
367
/**
368
 * Return a pointer to the end of the buffer content.
369
 *
370
 * @param buf  the buffer
371
 * @returns  the end of the internal content or NULL in case of error
372
 */
373
xmlChar *
374
xmlBufEnd(xmlBuf *buf)
375
241M
{
376
241M
    if ((!buf) || (BUF_ERROR(buf)))
377
0
        return NULL;
378
379
241M
    return(&buf->content[buf->use]);
380
241M
}
381
382
/**
383
 * Increase the size of the buffer content.
384
 *
385
 * If data was appended by writing directly into the content
386
 * array, this function increases the buffer size.
387
 *
388
 * @param buf  the buffer
389
 * @param len  number of bytes to add
390
 * @returns  0 on success, -1 in case of error
391
 */
392
int
393
241M
xmlBufAddLen(xmlBuf *buf, size_t len) {
394
241M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
395
0
        return(-1);
396
241M
    if (len > buf->size - buf->use)
397
0
        return(-1);
398
241M
    buf->use += len;
399
241M
    buf->content[buf->use] = 0;
400
241M
    return(0);
401
241M
}
402
403
/**
404
 * Return the size of the buffer content.
405
 *
406
 * @param buf  the buffer
407
 * @returns  size of buffer content in bytes
408
 */
409
size_t
410
xmlBufUse(xmlBuf *buf)
411
264M
{
412
264M
    if ((!buf) || (BUF_ERROR(buf)))
413
13
        return 0;
414
415
264M
    return(buf->use);
416
264M
}
417
418
/**
419
 * Return the size of available space at the end of a buffer.
420
 *
421
 * @param buf  the buffer
422
 * @returns  available space in bytes
423
 */
424
size_t
425
xmlBufAvail(xmlBuf *buf)
426
237M
{
427
237M
    if ((!buf) || (BUF_ERROR(buf)))
428
0
        return 0;
429
430
237M
    return(buf->size - buf->use);
431
237M
}
432
433
/**
434
 * Tell if a buffer is empty
435
 *
436
 * @param buf  the buffer
437
 * @returns  0 if no, 1 if yes and -1 in case of error
438
 */
439
int
440
xmlBufIsEmpty(xmlBuf *buf)
441
0
{
442
0
    if ((!buf) || (BUF_ERROR(buf)))
443
0
        return(-1);
444
445
0
    return(buf->use == 0);
446
0
}
447
448
/**
449
 * Append data to a buffer.
450
 *
451
 * If `len` is -1, `str` is expected to be zero-terminated.
452
 *
453
 * @param buf  the buffer
454
 * @param str  bytes to add
455
 * @param len  number of bytes
456
 * @returns  0 if successful, -1 in case of error.
457
 */
458
int
459
203M
xmlBufAdd(xmlBuf *buf, const xmlChar *str, size_t len) {
460
203M
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
461
658
        return(-1);
462
203M
    if (len == 0)
463
162k
        return(0);
464
203M
    if (str == NULL)
465
0
  return(-1);
466
467
203M
    if (len > buf->size - buf->use) {
468
1.31M
        if (xmlBufGrowInternal(buf, len) < 0)
469
65
            return(-1);
470
1.31M
    }
471
472
203M
    memmove(&buf->content[buf->use], str, len);
473
203M
    buf->use += len;
474
203M
    buf->content[buf->use] = 0;
475
476
203M
    return(0);
477
203M
}
478
479
/**
480
 * Append a zero-terminated string to a buffer.
481
 *
482
 * @param buf  the buffer
483
 * @param str  string (optional)
484
 * @returns  0 if successful, -1 in case of error.
485
 */
486
int
487
9.77M
xmlBufCat(xmlBuf *buf, const xmlChar *str) {
488
9.77M
    if (str == NULL)
489
0
        return(0);
490
9.77M
    return(xmlBufAdd(buf, str, strlen((const char *) str)));
491
9.77M
}
492
493
/**
494
 * Helper routine to switch from the old buffer structures in use
495
 * in various APIs. It creates a wrapper xmlBuf which will be
496
 * used for internal processing until xmlBufBackToBuffer is
497
 * issued.
498
 *
499
 * @param buffer  incoming old buffer to convert to a new one
500
 * @returns  a new xmlBuf unless the call failed and NULL is returned
501
 */
502
xmlBuf *
503
0
xmlBufFromBuffer(xmlBuffer *buffer) {
504
0
    xmlBufPtr ret;
505
506
0
    if (buffer == NULL)
507
0
        return(NULL);
508
509
0
    ret = xmlMalloc(sizeof(xmlBuf));
510
0
    if (ret == NULL)
511
0
        return(NULL);
512
513
0
    ret->use = buffer->use;
514
0
    ret->flags = 0;
515
0
    ret->maxSize = SIZE_MAX - 1;
516
517
0
    if (buffer->content == NULL) {
518
0
        ret->size = 50;
519
0
        ret->mem = xmlMalloc(ret->size + 1);
520
0
        ret->content = ret->mem;
521
0
        if (ret->mem == NULL)
522
0
            xmlBufMemoryError(ret);
523
0
        else
524
0
            ret->content[0] = 0;
525
0
    } else {
526
0
        ret->size = buffer->size - 1;
527
0
        ret->content = buffer->content;
528
0
        if (buffer->alloc == XML_BUFFER_ALLOC_IO)
529
0
            ret->mem = buffer->contentIO;
530
0
        else
531
0
            ret->mem = buffer->content;
532
0
    }
533
534
0
    return(ret);
535
0
}
536
537
/**
538
 * Function to be called once internal processing had been done to
539
 * update back the buffer provided by the user. This can lead to
540
 * a failure in case the size accumulated in the xmlBuf is larger
541
 * than what an xmlBuffer can support on 64 bits (INT_MAX)
542
 * The xmlBuf `buf` wrapper is deallocated by this call in any case.
543
 *
544
 * @param buf  new buffer wrapping the old one
545
 * @param ret  old buffer
546
 * @returns  0 on success, -1 on error.
547
 */
548
int
549
0
xmlBufBackToBuffer(xmlBuf *buf, xmlBuffer *ret) {
550
0
    if ((buf == NULL) || (ret == NULL))
551
0
        return(-1);
552
553
0
    if ((BUF_ERROR(buf)) || (BUF_STATIC(buf)) ||
554
0
        (buf->use >= INT_MAX)) {
555
0
        xmlBufFree(buf);
556
0
        ret->content = NULL;
557
0
        ret->contentIO = NULL;
558
0
        ret->use = 0;
559
0
        ret->size = 0;
560
0
        return(-1);
561
0
    }
562
563
0
    ret->use = buf->use;
564
0
    if (buf->size >= INT_MAX) {
565
        /* Keep the buffer but provide a truncated size value. */
566
0
        ret->size = INT_MAX;
567
0
    } else {
568
0
        ret->size = buf->size + 1;
569
0
    }
570
0
    ret->alloc = XML_BUFFER_ALLOC_IO;
571
0
    ret->content = buf->content;
572
0
    ret->contentIO = buf->mem;
573
0
    xmlFree(buf);
574
0
    return(0);
575
0
}
576
577
/**
578
 * Update pointers in the parser input struct.
579
 *
580
 * Update `base`, `cur` and `end` to point into the buffer.
581
 * This is required after the content array was reallocated.
582
 *
583
 * @param buf  a buffer
584
 * @param input  a parser input
585
 * @returns  0 on success, -1 in case of error.
586
 */
587
int
588
1.03M
xmlBufResetInput(xmlBuf *buf, xmlParserInput *input) {
589
1.03M
    return(xmlBufUpdateInput(buf, input, 0));
590
1.03M
}
591
592
/**
593
 * Update pointers in the parser input struct.
594
 *
595
 * Update `base`, `cur` and `end` to point into the buffer.
596
 * This is required after the content array was reallocated.
597
 *
598
 * @param buf  a buffer
599
 * @param input  a parser input
600
 * @param pos  the `cur` position relative to the start of the
601
 *             buffer
602
 * @returns  0 on success, -1 in case of error.
603
 */
604
int
605
34.6M
xmlBufUpdateInput(xmlBuf *buf, xmlParserInput *input, size_t pos) {
606
34.6M
    if ((buf == NULL) || (input == NULL))
607
0
        return(-1);
608
34.6M
    input->base = buf->content;
609
34.6M
    input->cur = input->base + pos;
610
34.6M
    input->end = &buf->content[buf->use];
611
34.6M
    return(0);
612
34.6M
}
613
614
/************************************************************************
615
 *                  *
616
 *      Old buffer implementation     *
617
 *                  *
618
 ************************************************************************/
619
620
/**
621
 * Set the buffer allocation scheme.
622
 *
623
 * @deprecated No-op, allocation schemes were removed.
624
 *
625
 * @param scheme  allocation method to use
626
 */
627
void
628
0
xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme ATTRIBUTE_UNUSED) {
629
0
}
630
631
/**
632
 * Get the buffer allocation scheme.
633
 *
634
 * @deprecated Allocation schemes were removed.
635
 *
636
 * @returns  the current allocation scheme
637
 */
638
xmlBufferAllocationScheme
639
0
xmlGetBufferAllocationScheme(void) {
640
0
    return(XML_BUFFER_ALLOC_EXACT);
641
0
}
642
643
/**
644
 * Create a buffer.
645
 *
646
 * The default initial size is 256.
647
 *
648
 * @returns  the new structure.
649
 */
650
xmlBuffer *
651
96.8k
xmlBufferCreate(void) {
652
96.8k
    xmlBufferPtr ret;
653
654
96.8k
    ret = xmlMalloc(sizeof(*ret));
655
96.8k
    if (ret == NULL)
656
189
        return(NULL);
657
658
96.6k
    ret->use = 0;
659
96.6k
    ret->size = 256;
660
96.6k
    ret->alloc = XML_BUFFER_ALLOC_IO;
661
96.6k
    ret->contentIO = xmlMalloc(ret->size);
662
96.6k
    if (ret->contentIO == NULL) {
663
15
  xmlFree(ret);
664
15
        return(NULL);
665
15
    }
666
96.6k
    ret->content = ret->contentIO;
667
96.6k
    ret->content[0] = 0;
668
669
96.6k
    return(ret);
670
96.6k
}
671
672
/**
673
 * Create a buffer with an initial size.
674
 *
675
 * @param size  initial size of buffer
676
 * @returns  the new structure.
677
 */
678
xmlBuffer *
679
350
xmlBufferCreateSize(size_t size) {
680
350
    xmlBufferPtr ret;
681
682
350
    if (size >= INT_MAX)
683
0
        return(NULL);
684
685
350
    ret = xmlMalloc(sizeof(*ret));
686
350
    if (ret == NULL)
687
2
        return(NULL);
688
689
348
    ret->use = 0;
690
348
    ret->alloc = XML_BUFFER_ALLOC_IO;
691
348
    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
692
693
348
    if (ret->size) {
694
348
        ret->contentIO = xmlMalloc(ret->size);
695
348
        if (ret->contentIO == NULL) {
696
1
            xmlFree(ret);
697
1
            return(NULL);
698
1
        }
699
347
        ret->content = ret->contentIO;
700
347
        ret->content[0] = 0;
701
347
    } else {
702
0
        ret->contentIO = NULL;
703
0
  ret->content = NULL;
704
0
    }
705
706
347
    return(ret);
707
348
}
708
709
/**
710
 * Extract buffer content.
711
 *
712
 * Return the contents of the buffer as an `xmlChar` string,
713
 * clearing the buffer.
714
 *
715
 * This doesn't work with static buffers as they can't be reset.
716
 *
717
 * @param buf  the buffer
718
 * @returns  the buffer content
719
 */
720
xmlChar *
721
347
xmlBufferDetach(xmlBuffer *buf) {
722
347
    xmlChar *ret;
723
724
347
    if (buf == NULL)
725
0
        return(NULL);
726
727
347
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
728
347
        (buf->content != buf->contentIO)) {
729
0
        ret = xmlStrndup(buf->content, buf->use);
730
0
        xmlFree(buf->contentIO);
731
347
    } else {
732
347
        ret = buf->content;
733
347
    }
734
735
347
    buf->contentIO = NULL;
736
347
    buf->content = NULL;
737
347
    buf->size = 0;
738
347
    buf->use = 0;
739
740
347
    return ret;
741
347
}
742
743
/**
744
 * Create a static buffer.
745
 *
746
 * The memory must be zero-terminated and not be modified for the
747
 * lifetime of the buffer. A static buffer can't be grown, modified or
748
 * detached, but it can be shrunk.
749
 *
750
 * @param mem  the memory area
751
 * @param size  the size in bytes
752
 * @returns  a new buffer
753
 */
754
xmlBuffer *
755
0
xmlBufferCreateStatic(void *mem, size_t size) {
756
0
    xmlBufferPtr buf = xmlBufferCreateSize(size);
757
758
0
    xmlBufferAdd(buf, mem, size);
759
0
    return(buf);
760
0
}
761
762
/**
763
 * Set the allocation scheme of a buffer.
764
 *
765
 * For libxml2 before 2.14, it is recommended to set this to
766
 * XML_BUFFER_ALLOC_DOUBLE_IT. Has no effect on 2.14 or later.
767
 *
768
 * @param buf  the buffer to tune
769
 * @param scheme  allocation scheme to use
770
 */
771
void
772
xmlBufferSetAllocationScheme(xmlBuffer *buf ATTRIBUTE_UNUSED,
773
15.9k
                             xmlBufferAllocationScheme scheme ATTRIBUTE_UNUSED) {
774
15.9k
}
775
776
/**
777
 * Free a buffer.
778
 *
779
 * @param buf  the buffer to free
780
 */
781
void
782
96.9k
xmlBufferFree(xmlBuffer *buf) {
783
96.9k
    if (buf == NULL)
784
0
  return;
785
786
96.9k
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
787
96.9k
        xmlFree(buf->contentIO);
788
0
    else
789
0
        xmlFree(buf->content);
790
791
96.9k
    xmlFree(buf);
792
96.9k
}
793
794
/**
795
 * Empty a buffer.
796
 *
797
 * @param buf  the buffer
798
 */
799
void
800
0
xmlBufferEmpty(xmlBuffer *buf) {
801
0
    if (buf == NULL)
802
0
        return;
803
0
    if (buf->content == NULL)
804
0
        return;
805
806
0
    buf->use = 0;
807
808
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
809
0
  buf->size += buf->content - buf->contentIO;
810
0
        buf->content = buf->contentIO;
811
0
        buf->content[0] = 0;
812
0
    } else {
813
0
        buf->content[0] = 0;
814
0
    }
815
0
}
816
817
/**
818
 * Discard bytes at the start of a buffer.
819
 *
820
 * @deprecated Internal function, don't use.
821
 *
822
 * @param buf  the buffer
823
 * @param len  the number of bytes to remove
824
 * @returns  the number of bytes removed, or -1 in case of failure.
825
 */
826
int
827
0
xmlBufferShrink(xmlBuffer *buf, unsigned int len) {
828
0
    if (buf == NULL)
829
0
        return(-1);
830
0
    if (len == 0)
831
0
        return(0);
832
0
    if (len > buf->use)
833
0
        return(-1);
834
835
0
    buf->use -= len;
836
837
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
838
0
        buf->content += len;
839
0
  buf->size -= len;
840
0
    } else {
841
0
  memmove(buf->content, &buf->content[len], buf->use + 1);
842
0
    }
843
844
0
    return(len);
845
0
}
846
847
/**
848
 * Grow a buffer.
849
 *
850
 * @deprecated Internal function, don't use.
851
 *
852
 * @param buf  the buffer
853
 * @param len  number of extra bytes to allocate
854
 * @returns  the new available space or -1 in case of error
855
 */
856
int
857
4.77k
xmlBufferGrow(xmlBuffer *buf, unsigned int len) {
858
4.77k
    unsigned int size;
859
4.77k
    xmlChar *newbuf;
860
861
4.77k
    if (buf == NULL)
862
0
        return(-1);
863
864
4.77k
    if (len < buf->size - buf->use)
865
0
        return(0);
866
4.77k
    if (len >= INT_MAX - buf->use)
867
0
        return(-1);
868
869
4.77k
    if (buf->size > (size_t) len) {
870
3.98k
        if (buf->size <= INT_MAX / 2)
871
3.98k
            size = buf->size * 2;
872
0
        else
873
0
            size = INT_MAX;
874
3.98k
    } else {
875
784
        size = buf->use + len + 1;
876
784
        if (size <= INT_MAX - 100)
877
784
            size += 100;
878
784
    }
879
880
4.77k
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
881
4.77k
        (buf->content != buf->contentIO)) {
882
0
        newbuf = xmlMalloc(size);
883
0
        if (newbuf == NULL)
884
0
            return(-1);
885
0
        if (buf->content != NULL)
886
0
            memcpy(newbuf, buf->content, buf->use + 1);
887
0
        xmlFree(buf->contentIO);
888
4.77k
    } else {
889
4.77k
        newbuf = xmlRealloc(buf->content, size);
890
4.77k
        if (newbuf == NULL)
891
264
            return(-1);
892
4.77k
    }
893
894
4.50k
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
895
4.50k
        buf->contentIO = newbuf;
896
4.50k
    buf->content = newbuf;
897
4.50k
    buf->size = size;
898
899
4.50k
    return(buf->size - buf->use - 1);
900
4.77k
}
901
902
/**
903
 * Dump a buffer to a `FILE`.
904
 *
905
 * @param file  the output file
906
 * @param buf  the buffer
907
 * @returns  the number of bytes written
908
 */
909
int
910
0
xmlBufferDump(FILE *file, xmlBuffer *buf) {
911
0
    size_t ret;
912
913
0
    if (buf == NULL)
914
0
  return(0);
915
0
    if (buf->content == NULL)
916
0
  return(0);
917
0
    if (file == NULL)
918
0
  file = stdout;
919
0
    ret = fwrite(buf->content, 1, buf->use, file);
920
0
    return(ret > INT_MAX ? INT_MAX : ret);
921
0
}
922
923
/**
924
 * Get pointer into buffer content.
925
 *
926
 * @param buf  the buffer
927
 * @returns  the internal content
928
 */
929
const xmlChar *
930
xmlBufferContent(const xmlBuffer *buf)
931
96.6k
{
932
96.6k
    if(!buf)
933
0
        return NULL;
934
935
96.6k
    return buf->content;
936
96.6k
}
937
938
/**
939
 * Get the size of the buffer content.
940
 *
941
 * @param buf  the buffer
942
 * @returns  the size of the buffer content in bytes
943
 */
944
int
945
xmlBufferLength(const xmlBuffer *buf)
946
15.5k
{
947
15.5k
    if(!buf)
948
0
        return 0;
949
950
15.5k
    return buf->use;
951
15.5k
}
952
953
/**
954
 * Resize a buffer to a minimum size.
955
 *
956
 * @deprecated Internal function, don't use.
957
 *
958
 * @param buf  the buffer to resize
959
 * @param size  the desired size
960
 * @returns  1 on succes, 0 in case of error
961
 */
962
int
963
xmlBufferResize(xmlBuffer *buf, unsigned int size)
964
0
{
965
0
    int res;
966
967
0
    if (buf == NULL)
968
0
        return(0);
969
0
    if (size < buf->size)
970
0
        return(1);
971
0
    res = xmlBufferGrow(buf, size - buf->use);
972
973
0
    return(res < 0 ? 0 : 1);
974
0
}
975
976
/**
977
 * Append bytes to a buffer.
978
 *
979
 * If `len` is -1, `str` is assumed to be zero-terminated.
980
 *
981
 * @param buf  the buffer
982
 * @param str  bytes to add 
983
 * @param len  number of bytes
984
 * @returns  an xmlParserErrors code.
985
 */
986
int
987
1.56M
xmlBufferAdd(xmlBuffer *buf, const xmlChar *str, int len) {
988
1.56M
    if ((buf == NULL) || (str == NULL))
989
0
  return(XML_ERR_ARGUMENT);
990
1.56M
    if (len < 0)
991
390k
        len = xmlStrlen(str);
992
1.56M
    if (len == 0)
993
505
        return(XML_ERR_OK);
994
995
    /* Note that both buf->size and buf->use can be zero here. */
996
1.56M
    if ((unsigned) len >= buf->size - buf->use) {
997
4.77k
        if (xmlBufferGrow(buf, len) < 0)
998
264
            return(XML_ERR_NO_MEMORY);
999
4.77k
    }
1000
1001
1.56M
    memmove(&buf->content[buf->use], str, len);
1002
1.56M
    buf->use += len;
1003
1.56M
    buf->content[buf->use] = 0;
1004
1.56M
    return(XML_ERR_OK);
1005
1.56M
}
1006
1007
/**
1008
 * Prepend bytes to a buffer.
1009
 *
1010
 * If `len` is -1, `str` is assumed to be zero-terminated.
1011
 *
1012
 * @param buf  the buffer
1013
 * @param str  bytes to prepend
1014
 * @param len  number of bytes
1015
 * @returns  an xmlParserErrors code.
1016
 */
1017
int
1018
0
xmlBufferAddHead(xmlBuffer *buf, const xmlChar *str, int len) {
1019
0
    unsigned start = 0;
1020
1021
0
    if ((buf == NULL) || (str == NULL))
1022
0
  return(XML_ERR_ARGUMENT);
1023
0
    if (len < 0)
1024
0
        len = xmlStrlen(str);
1025
0
    if (len == 0)
1026
0
        return(XML_ERR_OK);
1027
1028
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO) {
1029
0
        start = buf->content - buf->contentIO;
1030
1031
        /*
1032
         * We can add it in the space previously shrunk
1033
         */
1034
0
        if ((unsigned) len <= start) {
1035
0
            buf->content -= len;
1036
0
            memmove(&buf->content[0], str, len);
1037
0
            buf->use += len;
1038
0
            buf->size += len;
1039
0
            return(0);
1040
0
        }
1041
0
        if ((unsigned) len < buf->size + start - buf->use) {
1042
0
            memmove(&buf->contentIO[len], buf->content, buf->use + 1);
1043
0
            memmove(buf->contentIO, str, len);
1044
0
            buf->content = buf->contentIO;
1045
0
            buf->use += len;
1046
0
            buf->size += start;
1047
0
            return(0);
1048
0
        }
1049
0
    }
1050
1051
0
    if ((unsigned) len >= buf->size - buf->use) {
1052
0
        if (xmlBufferGrow(buf, len) < 0)
1053
0
            return(-1);
1054
0
    }
1055
1056
0
    memmove(&buf->content[len], buf->content, buf->use + 1);
1057
0
    memmove(buf->content, str, len);
1058
0
    buf->use += len;
1059
0
    return (0);
1060
0
}
1061
1062
/**
1063
 * Append a zero-terminated string to a buffer.
1064
 *
1065
 * @param buf  the buffer
1066
 * @param str  string to add
1067
 * @returns  an xmlParserErrors code.
1068
 */
1069
int
1070
82.5k
xmlBufferCat(xmlBuffer *buf, const xmlChar *str) {
1071
82.5k
    return(xmlBufferAdd(buf, str, -1));
1072
82.5k
}
1073
1074
/**
1075
 * Append a zero-terminated C string to a buffer.
1076
 *
1077
 * @param buf  the buffer
1078
 * @param str  string to add
1079
 * @returns  an xmlParserErrors code.
1080
 */
1081
int
1082
307k
xmlBufferCCat(xmlBuffer *buf, const char *str) {
1083
307k
    return(xmlBufferAdd(buf, (const xmlChar *) str, -1));
1084
307k
}
1085
1086
/**
1087
 * Append a zero-terminated `xmlChar` string to a buffer.
1088
 *
1089
 * @param buf  the XML buffer
1090
 * @param string  the string to add
1091
 */
1092
void
1093
0
xmlBufferWriteCHAR(xmlBuffer *buf, const xmlChar *string) {
1094
0
    xmlBufferAdd(buf, string, -1);
1095
0
}
1096
1097
/**
1098
 * Append a zero-terminated C string to a buffer.
1099
 *
1100
 * Same as #xmlBufferCCat.
1101
 *
1102
 * @param buf  the buffer
1103
 * @param string  the string to add
1104
 */
1105
void
1106
0
xmlBufferWriteChar(xmlBuffer *buf, const char *string) {
1107
0
    xmlBufferAdd(buf, (const xmlChar *) string, -1);
1108
0
}
1109
1110
/**
1111
 * Append a quoted string to a buffer.
1112
 *
1113
 * Append a string quoted with single or double quotes. If the
1114
 * string contains both single and double quotes, double quotes
1115
 * are escaped with `&quot;`.
1116
 *
1117
 * @param buf  the buffer
1118
 * @param string  the string to add
1119
 */
1120
void
1121
0
xmlBufferWriteQuotedString(xmlBuffer *buf, const xmlChar *string) {
1122
0
    const xmlChar *cur, *base;
1123
0
    if (buf == NULL)
1124
0
        return;
1125
0
    if (xmlStrchr(string, '\"')) {
1126
0
        if (xmlStrchr(string, '\'')) {
1127
0
      xmlBufferCCat(buf, "\"");
1128
0
            base = cur = string;
1129
0
            while(*cur != 0){
1130
0
                if(*cur == '"'){
1131
0
                    if (base != cur)
1132
0
                        xmlBufferAdd(buf, base, cur - base);
1133
0
                    xmlBufferAdd(buf, BAD_CAST "&quot;", 6);
1134
0
                    cur++;
1135
0
                    base = cur;
1136
0
                }
1137
0
                else {
1138
0
                    cur++;
1139
0
                }
1140
0
            }
1141
0
            if (base != cur)
1142
0
                xmlBufferAdd(buf, base, cur - base);
1143
0
      xmlBufferCCat(buf, "\"");
1144
0
  }
1145
0
        else{
1146
0
      xmlBufferCCat(buf, "\'");
1147
0
            xmlBufferCat(buf, string);
1148
0
      xmlBufferCCat(buf, "\'");
1149
0
        }
1150
0
    } else {
1151
0
        xmlBufferCCat(buf, "\"");
1152
0
        xmlBufferCat(buf, string);
1153
0
        xmlBufferCCat(buf, "\"");
1154
0
    }
1155
0
}
1156