Coverage Report

Created: 2025-07-07 10:01

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