Coverage Report

Created: 2025-06-22 06:55

/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
6.78M
#define BUF_FLAG_OOM        (1u << 0)
31
6.78M
#define BUF_FLAG_OVERFLOW   (1u << 1)
32
135k
#define BUF_FLAG_STATIC     (1u << 2)
33
34
6.78M
#define BUF_ERROR(buf) ((buf)->flags & (BUF_FLAG_OOM | BUF_FLAG_OVERFLOW))
35
102k
#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
0
{
61
0
    if (!BUF_ERROR(buf))
62
0
        buf->flags |= BUF_FLAG_OOM;
63
0
}
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.62k
xmlBufCreate(size_t size) {
86
1.62k
    xmlBufPtr ret;
87
88
1.62k
    if (size == SIZE_MAX)
89
0
        return(NULL);
90
91
1.62k
    ret = xmlMalloc(sizeof(*ret));
92
1.62k
    if (ret == NULL)
93
0
        return(NULL);
94
95
1.62k
    ret->use = 0;
96
1.62k
    ret->flags = 0;
97
1.62k
    ret->size = size;
98
1.62k
    ret->maxSize = SIZE_MAX - 1;
99
100
1.62k
    ret->mem = xmlMalloc(ret->size + 1);
101
1.62k
    if (ret->mem == NULL) {
102
0
        xmlFree(ret);
103
0
        return(NULL);
104
0
    }
105
1.62k
    ret->content = ret->mem;
106
1.62k
    ret->content[0] = 0;
107
108
1.62k
    return(ret);
109
1.62k
}
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
48.2k
xmlBufCreateMem(const xmlChar *mem, size_t size, int isStatic) {
126
48.2k
    xmlBufPtr ret;
127
128
48.2k
    if (mem == NULL)
129
0
        return(NULL);
130
131
48.2k
    ret = xmlMalloc(sizeof(*ret));
132
48.2k
    if (ret == NULL)
133
0
        return(NULL);
134
135
48.2k
    if (isStatic) {
136
        /* Check that memory is zero-terminated */
137
33.1k
        if (mem[size] != 0) {
138
0
            xmlFree(ret);
139
0
            return(NULL);
140
0
        }
141
33.1k
        ret->flags = BUF_FLAG_STATIC;
142
33.1k
        ret->mem = (xmlChar *) mem;
143
33.1k
    } else {
144
15.1k
        ret->flags = 0;
145
15.1k
        ret->mem = xmlMalloc(size + 1);
146
15.1k
        if (ret->mem == NULL) {
147
0
            xmlFree(ret);
148
0
            return(NULL);
149
0
        }
150
15.1k
        memcpy(ret->mem, mem, size);
151
15.1k
        ret->mem[size] = 0;
152
15.1k
    }
153
154
48.2k
    ret->use = size;
155
48.2k
    ret->size = size;
156
48.2k
    ret->maxSize = SIZE_MAX - 1;
157
48.2k
    ret->content = ret->mem;
158
159
48.2k
    return(ret);
160
48.2k
}
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
0
xmlBufDetach(xmlBuf *buf) {
175
0
    xmlChar *ret;
176
177
0
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
178
0
        return(NULL);
179
180
0
    if (buf->content != buf->mem) {
181
0
        ret = xmlStrndup(buf->content, buf->use);
182
0
        xmlFree(buf->mem);
183
0
    } else {
184
0
        ret = buf->mem;
185
0
    }
186
187
0
    buf->content = NULL;
188
0
    buf->mem = NULL;
189
0
    buf->size = 0;
190
0
    buf->use = 0;
191
192
0
    return ret;
193
0
}
194
195
/**
196
 * Free a buffer.
197
 *
198
 * @param buf  the buffer to free
199
 */
200
void
201
49.8k
xmlBufFree(xmlBuf *buf) {
202
49.8k
    if (buf == NULL)
203
0
  return;
204
205
49.8k
    if (!BUF_STATIC(buf))
206
16.7k
        xmlFree(buf->mem);
207
49.8k
    xmlFree(buf);
208
49.8k
}
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
6.44M
xmlBufShrink(xmlBuf *buf, size_t len) {
243
6.44M
    if ((buf == NULL) || (BUF_ERROR(buf)))
244
0
        return(0);
245
6.44M
    if (len == 0)
246
11.0k
        return(0);
247
248
6.43M
    if (len > buf->use)
249
0
        return(0);
250
251
6.43M
    buf->use -= len;
252
6.43M
    buf->content += len;
253
6.43M
    buf->size -= len;
254
255
6.43M
    return(len);
256
6.43M
}
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
4.27k
xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
272
4.27k
    size_t size;
273
4.27k
    size_t start;
274
4.27k
    xmlChar *newbuf;
275
276
    /*
277
     * If there's enough space at the start of the buffer,
278
     * move the contents.
279
     */
280
4.27k
    start = buf->content - buf->mem;
281
4.27k
    if (len <= start + buf->size - buf->use) {
282
1.96k
        memmove(buf->mem, buf->content, buf->use + 1);
283
1.96k
        buf->size += start;
284
1.96k
        buf->content = buf->mem;
285
1.96k
        return(0);
286
1.96k
    }
287
288
2.30k
    if (len > buf->maxSize - buf->use) {
289
0
        xmlBufOverflowError(buf);
290
0
        return(-1);
291
0
    }
292
293
2.30k
    if (buf->size > (size_t) len) {
294
1.58k
        if (buf->size <= buf->maxSize / 2)
295
1.58k
            size = buf->size * 2;
296
0
        else
297
0
            size = buf->maxSize;
298
1.58k
    } else {
299
723
        size = buf->use + len;
300
723
        if (size <= buf->maxSize - 100)
301
723
            size += 100;
302
723
    }
303
304
2.30k
    if (buf->content == buf->mem) {
305
1.37k
        newbuf = xmlRealloc(buf->mem, size + 1);
306
1.37k
        if (newbuf == NULL) {
307
0
            xmlBufMemoryError(buf);
308
0
            return(-1);
309
0
        }
310
1.37k
    } else {
311
937
        newbuf = xmlMalloc(size + 1);
312
937
        if (newbuf == NULL) {
313
0
            xmlBufMemoryError(buf);
314
0
            return(-1);
315
0
        }
316
937
        if (buf->content != NULL)
317
937
            memcpy(newbuf, buf->content, buf->use + 1);
318
937
        xmlFree(buf->mem);
319
937
    }
320
321
2.30k
    buf->mem = newbuf;
322
2.30k
    buf->content = newbuf;
323
2.30k
    buf->size = size;
324
325
2.30k
    return(0);
326
2.30k
}
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
4.27k
xmlBufGrow(xmlBuf *buf, size_t len) {
340
4.27k
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
341
0
        return(-1);
342
343
4.27k
    if (len <= buf->size - buf->use)
344
0
        return(0);
345
346
4.27k
    if (xmlBufGrowInternal(buf, len) < 0)
347
0
        return(-1);
348
349
4.27k
    return(0);
350
4.27k
}
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
43.9k
{
361
43.9k
    if ((!buf) || (BUF_ERROR(buf)))
362
0
        return NULL;
363
364
43.9k
    return(buf->content);
365
43.9k
}
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
48.1k
{
376
48.1k
    if ((!buf) || (BUF_ERROR(buf)))
377
0
        return NULL;
378
379
48.1k
    return(&buf->content[buf->use]);
380
48.1k
}
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
48.1k
xmlBufAddLen(xmlBuf *buf, size_t len) {
394
48.1k
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
395
0
        return(-1);
396
48.1k
    if (len > buf->size - buf->use)
397
0
        return(-1);
398
48.1k
    buf->use += len;
399
48.1k
    buf->content[buf->use] = 0;
400
48.1k
    return(0);
401
48.1k
}
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
149k
{
412
149k
    if ((!buf) || (BUF_ERROR(buf)))
413
0
        return 0;
414
415
149k
    return(buf->use);
416
149k
}
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
48.1k
{
427
48.1k
    if ((!buf) || (BUF_ERROR(buf)))
428
0
        return 0;
429
430
48.1k
    return(buf->size - buf->use);
431
48.1k
}
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
0
xmlBufAdd(xmlBuf *buf, const xmlChar *str, size_t len) {
460
0
    if ((buf == NULL) || (BUF_ERROR(buf)) || (BUF_STATIC(buf)))
461
0
        return(-1);
462
0
    if (len == 0)
463
0
        return(0);
464
0
    if (str == NULL)
465
0
  return(-1);
466
467
0
    if (len > buf->size - buf->use) {
468
0
        if (xmlBufGrowInternal(buf, len) < 0)
469
0
            return(-1);
470
0
    }
471
472
0
    memmove(&buf->content[buf->use], str, len);
473
0
    buf->use += len;
474
0
    buf->content[buf->use] = 0;
475
476
0
    return(0);
477
0
}
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
0
xmlBufCat(xmlBuf *buf, const xmlChar *str) {
488
0
    if (str == NULL)
489
0
        return(0);
490
0
    return(xmlBufAdd(buf, str, strlen((const char *) str)));
491
0
}
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
49.8k
xmlBufResetInput(xmlBuf *buf, xmlParserInput *input) {
589
49.8k
    return(xmlBufUpdateInput(buf, input, 0));
590
49.8k
}
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
6.59M
xmlBufUpdateInput(xmlBuf *buf, xmlParserInput *input, size_t pos) {
606
6.59M
    if ((buf == NULL) || (input == NULL))
607
0
        return(-1);
608
6.59M
    input->base = buf->content;
609
6.59M
    input->cur = input->base + pos;
610
6.59M
    input->end = &buf->content[buf->use];
611
6.59M
    return(0);
612
6.59M
}
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
0
xmlBufferCreate(void) {
652
0
    xmlBufferPtr ret;
653
654
0
    ret = xmlMalloc(sizeof(*ret));
655
0
    if (ret == NULL)
656
0
        return(NULL);
657
658
0
    ret->use = 0;
659
0
    ret->size = 256;
660
0
    ret->alloc = XML_BUFFER_ALLOC_IO;
661
0
    ret->contentIO = xmlMalloc(ret->size);
662
0
    if (ret->contentIO == NULL) {
663
0
  xmlFree(ret);
664
0
        return(NULL);
665
0
    }
666
0
    ret->content = ret->contentIO;
667
0
    ret->content[0] = 0;
668
669
0
    return(ret);
670
0
}
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
0
xmlBufferCreateSize(size_t size) {
680
0
    xmlBufferPtr ret;
681
682
0
    if (size >= INT_MAX)
683
0
        return(NULL);
684
685
0
    ret = xmlMalloc(sizeof(*ret));
686
0
    if (ret == NULL)
687
0
        return(NULL);
688
689
0
    ret->use = 0;
690
0
    ret->alloc = XML_BUFFER_ALLOC_IO;
691
0
    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
692
693
0
    if (ret->size) {
694
0
        ret->contentIO = xmlMalloc(ret->size);
695
0
        if (ret->contentIO == NULL) {
696
0
            xmlFree(ret);
697
0
            return(NULL);
698
0
        }
699
0
        ret->content = ret->contentIO;
700
0
        ret->content[0] = 0;
701
0
    } else {
702
0
        ret->contentIO = NULL;
703
0
  ret->content = NULL;
704
0
    }
705
706
0
    return(ret);
707
0
}
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
0
xmlBufferDetach(xmlBuffer *buf) {
722
0
    xmlChar *ret;
723
724
0
    if (buf == NULL)
725
0
        return(NULL);
726
727
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
728
0
        (buf->content != buf->contentIO)) {
729
0
        ret = xmlStrndup(buf->content, buf->use);
730
0
        xmlFree(buf->contentIO);
731
0
    } else {
732
0
        ret = buf->content;
733
0
    }
734
735
0
    buf->contentIO = NULL;
736
0
    buf->content = NULL;
737
0
    buf->size = 0;
738
0
    buf->use = 0;
739
740
0
    return ret;
741
0
}
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
0
                             xmlBufferAllocationScheme scheme ATTRIBUTE_UNUSED) {
774
0
}
775
776
/**
777
 * Free a buffer.
778
 *
779
 * @param buf  the buffer to free
780
 */
781
void
782
0
xmlBufferFree(xmlBuffer *buf) {
783
0
    if (buf == NULL)
784
0
  return;
785
786
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
787
0
        xmlFree(buf->contentIO);
788
0
    else
789
0
        xmlFree(buf->content);
790
791
0
    xmlFree(buf);
792
0
}
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
0
xmlBufferGrow(xmlBuffer *buf, unsigned int len) {
858
0
    unsigned int size;
859
0
    xmlChar *newbuf;
860
861
0
    if (buf == NULL)
862
0
        return(-1);
863
864
0
    if (len < buf->size - buf->use)
865
0
        return(0);
866
0
    if (len >= INT_MAX - buf->use)
867
0
        return(-1);
868
869
0
    if (buf->size > (size_t) len) {
870
0
        if (buf->size <= INT_MAX / 2)
871
0
            size = buf->size * 2;
872
0
        else
873
0
            size = INT_MAX;
874
0
    } else {
875
0
        size = buf->use + len + 1;
876
0
        if (size <= INT_MAX - 100)
877
0
            size += 100;
878
0
    }
879
880
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
881
0
        (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
0
    } else {
889
0
        newbuf = xmlRealloc(buf->content, size);
890
0
        if (newbuf == NULL)
891
0
            return(-1);
892
0
    }
893
894
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
895
0
        buf->contentIO = newbuf;
896
0
    buf->content = newbuf;
897
0
    buf->size = size;
898
899
0
    return(buf->size - buf->use - 1);
900
0
}
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
0
{
932
0
    if(!buf)
933
0
        return NULL;
934
935
0
    return buf->content;
936
0
}
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
0
{
947
0
    if(!buf)
948
0
        return 0;
949
950
0
    return buf->use;
951
0
}
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
0
xmlBufferAdd(xmlBuffer *buf, const xmlChar *str, int len) {
988
0
    if ((buf == NULL) || (str == NULL))
989
0
  return(XML_ERR_ARGUMENT);
990
0
    if (len < 0)
991
0
        len = xmlStrlen(str);
992
0
    if (len == 0)
993
0
        return(XML_ERR_OK);
994
995
    /* Note that both buf->size and buf->use can be zero here. */
996
0
    if ((unsigned) len >= buf->size - buf->use) {
997
0
        if (xmlBufferGrow(buf, len) < 0)
998
0
            return(XML_ERR_NO_MEMORY);
999
0
    }
1000
1001
0
    memmove(&buf->content[buf->use], str, len);
1002
0
    buf->use += len;
1003
0
    buf->content[buf->use] = 0;
1004
0
    return(XML_ERR_OK);
1005
0
}
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
0
xmlBufferCat(xmlBuffer *buf, const xmlChar *str) {
1071
0
    return(xmlBufferAdd(buf, str, -1));
1072
0
}
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
0
xmlBufferCCat(xmlBuffer *buf, const char *str) {
1083
0
    return(xmlBufferAdd(buf, (const xmlChar *) str, -1));
1084
0
}
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