Coverage Report

Created: 2026-05-30 06:18

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