Coverage Report

Created: 2025-07-11 06:47

/src/tinysparql/subprojects/libxml2-2.13.1/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> /* for memset() only ! */
19
#include <limits.h>
20
#include <ctype.h>
21
#include <stdlib.h>
22
23
#include <libxml/tree.h>
24
#include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
25
26
#include "private/buf.h"
27
#include "private/error.h"
28
29
#ifndef SIZE_MAX
30
0
#define SIZE_MAX ((size_t) -1)
31
#endif
32
33
#define WITH_BUFFER_COMPAT
34
35
/**
36
 * xmlBuf:
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
    unsigned int compat_use;    /* for binary compatibility */
46
    unsigned int compat_size;   /* for binary compatibility */
47
    xmlBufferAllocationScheme alloc; /* The realloc method */
48
    xmlChar *contentIO;   /* in IO mode we may have a different base */
49
    size_t use;           /* The buffer size used */
50
    size_t size;    /* The buffer size */
51
    xmlBufferPtr buffer;        /* wrapper for an old buffer */
52
    int error;                  /* an error code if a failure occurred */
53
};
54
55
#ifdef WITH_BUFFER_COMPAT
56
/*
57
 * Macro for compatibility with xmlBuffer to be used after an xmlBuf
58
 * is updated. This makes sure the compat fields are updated too.
59
 */
60
#define UPDATE_COMPAT(buf)            \
61
0
     if (buf->size < INT_MAX) buf->compat_size = buf->size; \
62
0
     else buf->compat_size = INT_MAX;         \
63
0
     if (buf->use < INT_MAX) buf->compat_use = buf->use; \
64
0
     else buf->compat_use = INT_MAX;
65
66
/*
67
 * Macro for compatibility with xmlBuffer to be used in all the xmlBuf
68
 * entry points, it checks that the compat fields have not been modified
69
 * by direct call to xmlBuffer function from code compiled before 2.9.0 .
70
 */
71
#define CHECK_COMPAT(buf)           \
72
0
     if (buf->size != (size_t) buf->compat_size)     \
73
0
         if (buf->compat_size < INT_MAX)       \
74
0
       buf->size = buf->compat_size;       \
75
0
     if (buf->use != (size_t) buf->compat_use)       \
76
0
         if (buf->compat_use < INT_MAX)         \
77
0
       buf->use = buf->compat_use;
78
79
#else /* ! WITH_BUFFER_COMPAT */
80
#define UPDATE_COMPAT(buf)
81
#define CHECK_COMPAT(buf)
82
#endif /* WITH_BUFFER_COMPAT */
83
84
/**
85
 * xmlBufMemoryError:
86
 * @extra:  extra information
87
 *
88
 * Handle an out of memory condition
89
 * To be improved...
90
 */
91
static void
92
xmlBufMemoryError(xmlBufPtr buf)
93
0
{
94
0
    if (buf->error == 0)
95
0
        buf->error = XML_ERR_NO_MEMORY;
96
0
}
97
98
/**
99
 * xmlBufOverflowError:
100
 * @extra:  extra information
101
 *
102
 * Handle a buffer overflow error
103
 * To be improved...
104
 */
105
static void
106
xmlBufOverflowError(xmlBufPtr buf)
107
0
{
108
0
    if (buf->error == 0)
109
0
        buf->error = XML_BUF_OVERFLOW;
110
0
}
111
112
113
/**
114
 * xmlBufCreate:
115
 *
116
 * routine to create an XML buffer.
117
 * returns the new structure.
118
 */
119
xmlBufPtr
120
0
xmlBufCreate(void) {
121
0
    xmlBufPtr ret;
122
123
0
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
124
0
    if (ret == NULL)
125
0
        return(NULL);
126
0
    ret->use = 0;
127
0
    ret->error = 0;
128
0
    ret->buffer = NULL;
129
0
    ret->size = xmlDefaultBufferSize;
130
0
    UPDATE_COMPAT(ret);
131
0
    ret->alloc = xmlBufferAllocScheme;
132
0
    ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
133
0
    if (ret->content == NULL) {
134
0
  xmlFree(ret);
135
0
        return(NULL);
136
0
    }
137
0
    ret->content[0] = 0;
138
0
    ret->contentIO = NULL;
139
0
    return(ret);
140
0
}
141
142
/**
143
 * xmlBufCreateSize:
144
 * @size: initial size of buffer
145
 *
146
 * routine to create an XML buffer.
147
 * returns the new structure.
148
 */
149
xmlBufPtr
150
0
xmlBufCreateSize(size_t size) {
151
0
    xmlBufPtr ret;
152
153
0
    if (size == SIZE_MAX)
154
0
        return(NULL);
155
0
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
156
0
    if (ret == NULL)
157
0
        return(NULL);
158
0
    ret->use = 0;
159
0
    ret->error = 0;
160
0
    ret->buffer = NULL;
161
0
    ret->alloc = xmlBufferAllocScheme;
162
0
    ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
163
0
    UPDATE_COMPAT(ret);
164
0
    if (ret->size){
165
0
        ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
166
0
        if (ret->content == NULL) {
167
0
            xmlFree(ret);
168
0
            return(NULL);
169
0
        }
170
0
        ret->content[0] = 0;
171
0
    } else
172
0
  ret->content = NULL;
173
0
    ret->contentIO = NULL;
174
0
    return(ret);
175
0
}
176
177
/**
178
 * xmlBufDetach:
179
 * @buf:  the buffer
180
 *
181
 * Remove the string contained in a buffer and give it back to the
182
 * caller. The buffer is reset to an empty content.
183
 * This doesn't work with immutable buffers as they can't be reset.
184
 *
185
 * Returns the previous string contained by the buffer.
186
 */
187
xmlChar *
188
0
xmlBufDetach(xmlBufPtr buf) {
189
0
    xmlChar *ret;
190
191
0
    if (buf == NULL)
192
0
        return(NULL);
193
0
    if (buf->buffer != NULL)
194
0
        return(NULL);
195
0
    if (buf->error)
196
0
        return(NULL);
197
198
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
199
0
        (buf->content != buf->contentIO)) {
200
0
        ret = xmlStrndup(buf->content, buf->use);
201
0
        xmlFree(buf->contentIO);
202
0
    } else {
203
0
        ret = buf->content;
204
0
    }
205
206
0
    buf->content = NULL;
207
0
    buf->contentIO = NULL;
208
0
    buf->size = 0;
209
0
    buf->use = 0;
210
0
    UPDATE_COMPAT(buf);
211
212
0
    return ret;
213
0
}
214
215
/**
216
 * xmlBufGetAllocationScheme:
217
 * @buf:  the buffer
218
 *
219
 * Get the buffer allocation scheme
220
 *
221
 * Returns the scheme or -1 in case of error
222
 */
223
int
224
0
xmlBufGetAllocationScheme(xmlBufPtr buf) {
225
0
    if (buf == NULL) {
226
0
        return(-1);
227
0
    }
228
0
    return(buf->alloc);
229
0
}
230
231
/**
232
 * xmlBufSetAllocationScheme:
233
 * @buf:  the buffer to tune
234
 * @scheme:  allocation scheme to use
235
 *
236
 * Sets the allocation scheme for this buffer
237
 *
238
 * returns 0 in case of success and -1 in case of failure
239
 */
240
int
241
xmlBufSetAllocationScheme(xmlBufPtr buf,
242
0
                          xmlBufferAllocationScheme scheme) {
243
0
    if ((buf == NULL) || (buf->error != 0)) {
244
0
        return(-1);
245
0
    }
246
0
    if (buf->alloc == XML_BUFFER_ALLOC_IO)
247
0
        return(-1);
248
0
    if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
249
0
        (scheme == XML_BUFFER_ALLOC_EXACT) ||
250
0
        (scheme == XML_BUFFER_ALLOC_HYBRID) ||
251
0
  (scheme == XML_BUFFER_ALLOC_BOUNDED)) {
252
0
  buf->alloc = scheme;
253
0
        if (buf->buffer)
254
0
            buf->buffer->alloc = scheme;
255
0
        return(0);
256
0
    }
257
    /*
258
     * Switching a buffer ALLOC_IO has the side effect of initializing
259
     * the contentIO field with the current content
260
     */
261
0
    if (scheme == XML_BUFFER_ALLOC_IO) {
262
0
        buf->alloc = XML_BUFFER_ALLOC_IO;
263
0
        buf->contentIO = buf->content;
264
0
    }
265
0
    return(-1);
266
0
}
267
268
/**
269
 * xmlBufFree:
270
 * @buf:  the buffer to free
271
 *
272
 * Frees an XML buffer. It frees both the content and the structure which
273
 * encapsulate it.
274
 */
275
void
276
0
xmlBufFree(xmlBufPtr buf) {
277
0
    if (buf == NULL) {
278
0
  return;
279
0
    }
280
281
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
282
0
        (buf->contentIO != NULL)) {
283
0
        xmlFree(buf->contentIO);
284
0
    } else if (buf->content != NULL) {
285
0
        xmlFree(buf->content);
286
0
    }
287
0
    xmlFree(buf);
288
0
}
289
290
/**
291
 * xmlBufEmpty:
292
 * @buf:  the buffer
293
 *
294
 * empty a buffer.
295
 */
296
void
297
0
xmlBufEmpty(xmlBufPtr buf) {
298
0
    if ((buf == NULL) || (buf->error != 0)) return;
299
0
    if (buf->content == NULL) return;
300
0
    CHECK_COMPAT(buf)
301
0
    buf->use = 0;
302
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
303
0
               (buf->contentIO != NULL)) {
304
0
        size_t start_buf = buf->content - buf->contentIO;
305
306
0
  buf->size += start_buf;
307
0
        buf->content = buf->contentIO;
308
0
        buf->content[0] = 0;
309
0
    } else {
310
0
        buf->content[0] = 0;
311
0
    }
312
0
    UPDATE_COMPAT(buf)
313
0
}
314
315
/**
316
 * xmlBufShrink:
317
 * @buf:  the buffer to dump
318
 * @len:  the number of xmlChar to remove
319
 *
320
 * Remove the beginning of an XML buffer.
321
 * NOTE that this routine behaviour differs from xmlBufferShrink()
322
 * as it will return 0 on error instead of -1 due to size_t being
323
 * used as the return type.
324
 *
325
 * Returns the number of byte removed or 0 in case of failure
326
 */
327
size_t
328
0
xmlBufShrink(xmlBufPtr buf, size_t len) {
329
0
    if ((buf == NULL) || (buf->error != 0)) return(0);
330
0
    CHECK_COMPAT(buf)
331
0
    if (len == 0) return(0);
332
0
    if (len > buf->use) return(0);
333
334
0
    buf->use -= len;
335
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
336
  /*
337
   * we just move the content pointer, but also make sure
338
   * the perceived buffer size has shrunk accordingly
339
   */
340
0
        buf->content += len;
341
0
  buf->size -= len;
342
343
        /*
344
   * sometimes though it maybe be better to really shrink
345
   * on IO buffers
346
   */
347
0
  if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
348
0
      size_t start_buf = buf->content - buf->contentIO;
349
0
      if (start_buf >= buf->size) {
350
0
    memmove(buf->contentIO, &buf->content[0], buf->use);
351
0
    buf->content = buf->contentIO;
352
0
    buf->content[buf->use] = 0;
353
0
    buf->size += start_buf;
354
0
      }
355
0
  }
356
0
    } else {
357
0
  memmove(buf->content, &buf->content[len], buf->use);
358
0
  buf->content[buf->use] = 0;
359
0
    }
360
0
    UPDATE_COMPAT(buf)
361
0
    return(len);
362
0
}
363
364
/**
365
 * xmlBufGrowInternal:
366
 * @buf:  the buffer
367
 * @len:  the minimum free size to allocate
368
 *
369
 * Grow the available space of an XML buffer, @len is the target value
370
 * Error checking should be done on buf->error since using the return
371
 * value doesn't work that well
372
 *
373
 * Returns 0 in case of error or the length made available otherwise
374
 */
375
static size_t
376
0
xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
377
0
    size_t size;
378
0
    xmlChar *newbuf;
379
380
0
    if ((buf == NULL) || (buf->error != 0)) return(0);
381
0
    CHECK_COMPAT(buf)
382
383
0
    if (len < buf->size - buf->use)
384
0
        return(buf->size - buf->use - 1);
385
0
    if (len >= SIZE_MAX - buf->use) {
386
0
        xmlBufMemoryError(buf);
387
0
        return(0);
388
0
    }
389
390
0
    if (buf->size > (size_t) len) {
391
0
        size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
392
0
    } else {
393
0
        size = buf->use + len;
394
0
        size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
395
0
    }
396
397
0
    if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
398
        /*
399
   * Used to provide parsing limits
400
   */
401
0
        if ((buf->use + len + 1 >= XML_MAX_TEXT_LENGTH) ||
402
0
      (buf->size >= XML_MAX_TEXT_LENGTH)) {
403
0
      xmlBufMemoryError(buf);
404
0
      return(0);
405
0
  }
406
0
  if (size >= XML_MAX_TEXT_LENGTH)
407
0
      size = XML_MAX_TEXT_LENGTH;
408
0
    }
409
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
410
0
        size_t start_buf = buf->content - buf->contentIO;
411
412
0
  newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
413
0
  if (newbuf == NULL) {
414
0
      xmlBufMemoryError(buf);
415
0
      return(0);
416
0
  }
417
0
  buf->contentIO = newbuf;
418
0
  buf->content = newbuf + start_buf;
419
0
    } else {
420
0
  newbuf = (xmlChar *) xmlRealloc(buf->content, size);
421
0
  if (newbuf == NULL) {
422
0
      xmlBufMemoryError(buf);
423
0
      return(0);
424
0
  }
425
0
  buf->content = newbuf;
426
0
    }
427
0
    buf->size = size;
428
0
    UPDATE_COMPAT(buf)
429
0
    return(buf->size - buf->use - 1);
430
0
}
431
432
/**
433
 * xmlBufGrow:
434
 * @buf:  the buffer
435
 * @len:  the minimum free size to allocate
436
 *
437
 * Grow the available space of an XML buffer, @len is the target value
438
 * This is been kept compatible with xmlBufferGrow() as much as possible
439
 *
440
 * Returns -1 in case of error or the length made available otherwise
441
 */
442
int
443
0
xmlBufGrow(xmlBufPtr buf, int len) {
444
0
    size_t ret;
445
446
0
    if ((buf == NULL) || (len < 0)) return(-1);
447
0
    if (len == 0)
448
0
        return(0);
449
0
    ret = xmlBufGrowInternal(buf, len);
450
0
    if (buf->error != 0)
451
0
        return(-1);
452
0
    return(ret > INT_MAX ? INT_MAX : ret);
453
0
}
454
455
/**
456
 * xmlBufDump:
457
 * @file:  the file output
458
 * @buf:  the buffer to dump
459
 *
460
 * Dumps an XML buffer to  a FILE *.
461
 * Returns the number of #xmlChar written
462
 */
463
size_t
464
0
xmlBufDump(FILE *file, xmlBufPtr buf) {
465
0
    size_t ret;
466
467
0
    if ((buf == NULL) || (buf->error != 0)) {
468
0
  return(0);
469
0
    }
470
0
    if (buf->content == NULL) {
471
0
  return(0);
472
0
    }
473
0
    CHECK_COMPAT(buf)
474
0
    if (file == NULL)
475
0
  file = stdout;
476
0
    ret = fwrite(buf->content, 1, buf->use, file);
477
0
    return(ret);
478
0
}
479
480
/**
481
 * xmlBufContent:
482
 * @buf:  the buffer
483
 *
484
 * Function to extract the content of a buffer
485
 *
486
 * Returns the internal content
487
 */
488
489
xmlChar *
490
xmlBufContent(const xmlBuf *buf)
491
0
{
492
0
    if ((!buf) || (buf->error))
493
0
        return NULL;
494
495
0
    return(buf->content);
496
0
}
497
498
/**
499
 * xmlBufEnd:
500
 * @buf:  the buffer
501
 *
502
 * Function to extract the end of the content of a buffer
503
 *
504
 * Returns the end of the internal content or NULL in case of error
505
 */
506
507
xmlChar *
508
xmlBufEnd(xmlBufPtr buf)
509
0
{
510
0
    if ((!buf) || (buf->error))
511
0
        return NULL;
512
0
    CHECK_COMPAT(buf)
513
514
0
    return(&buf->content[buf->use]);
515
0
}
516
517
/**
518
 * xmlBufAddLen:
519
 * @buf:  the buffer
520
 * @len:  the size which were added at the end
521
 *
522
 * Sometime data may be added at the end of the buffer without
523
 * using the xmlBuf APIs that is used to expand the used space
524
 * and set the zero terminating at the end of the buffer
525
 *
526
 * Returns -1 in case of error and 0 otherwise
527
 */
528
int
529
0
xmlBufAddLen(xmlBufPtr buf, size_t len) {
530
0
    if ((buf == NULL) || (buf->error))
531
0
        return(-1);
532
0
    CHECK_COMPAT(buf)
533
0
    if (len >= (buf->size - buf->use))
534
0
        return(-1);
535
0
    buf->use += len;
536
0
    buf->content[buf->use] = 0;
537
0
    UPDATE_COMPAT(buf)
538
0
    return(0);
539
0
}
540
541
/**
542
 * xmlBufLength:
543
 * @buf:  the buffer
544
 *
545
 * Function to get the length of a buffer
546
 *
547
 * Returns the length of data in the internal content
548
 */
549
550
size_t
551
xmlBufLength(const xmlBufPtr buf)
552
0
{
553
0
    if ((!buf) || (buf->error))
554
0
        return 0;
555
0
    CHECK_COMPAT(buf)
556
557
0
    return(buf->use);
558
0
}
559
560
/**
561
 * xmlBufUse:
562
 * @buf:  the buffer
563
 *
564
 * Function to get the length of a buffer
565
 *
566
 * Returns the length of data in the internal content
567
 */
568
569
size_t
570
xmlBufUse(const xmlBufPtr buf)
571
0
{
572
0
    if ((!buf) || (buf->error))
573
0
        return 0;
574
0
    CHECK_COMPAT(buf)
575
576
0
    return(buf->use);
577
0
}
578
579
/**
580
 * xmlBufAvail:
581
 * @buf:  the buffer
582
 *
583
 * Function to find how much free space is allocated but not
584
 * used in the buffer. It reserves one byte for the NUL
585
 * terminator character that is usually needed, so there is
586
 * no need to subtract 1 from the result anymore.
587
 *
588
 * Returns the amount, or 0 if none or if an error occurred.
589
 */
590
591
size_t
592
xmlBufAvail(const xmlBufPtr buf)
593
0
{
594
0
    if ((!buf) || (buf->error))
595
0
        return 0;
596
0
    CHECK_COMPAT(buf)
597
598
0
    return((buf->size > buf->use) ? (buf->size - buf->use - 1) : 0);
599
0
}
600
601
/**
602
 * xmlBufIsEmpty:
603
 * @buf:  the buffer
604
 *
605
 * Tell if a buffer is empty
606
 *
607
 * Returns 0 if no, 1 if yes and -1 in case of error
608
 */
609
int
610
xmlBufIsEmpty(const xmlBufPtr buf)
611
0
{
612
0
    if ((!buf) || (buf->error))
613
0
        return(-1);
614
0
    CHECK_COMPAT(buf)
615
616
0
    return(buf->use == 0);
617
0
}
618
619
/**
620
 * xmlBufResize:
621
 * @buf:  the buffer to resize
622
 * @size:  the desired size
623
 *
624
 * Resize a buffer to accommodate minimum size of @size.
625
 *
626
 * Returns  0 in case of problems, 1 otherwise
627
 */
628
int
629
xmlBufResize(xmlBufPtr buf, size_t size)
630
0
{
631
0
    size_t newSize;
632
0
    xmlChar* rebuf = NULL;
633
0
    size_t start_buf;
634
635
0
    if ((buf == NULL) || (buf->error))
636
0
        return(0);
637
0
    CHECK_COMPAT(buf)
638
639
0
    if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
640
        /*
641
   * Used to provide parsing limits
642
   */
643
0
        if (size >= XML_MAX_TEXT_LENGTH) {
644
0
      xmlBufMemoryError(buf);
645
0
      return(0);
646
0
  }
647
0
    }
648
649
    /* Don't resize if we don't have to */
650
0
    if (size < buf->size)
651
0
        return 1;
652
653
    /* figure out new size */
654
0
    switch (buf->alloc){
655
0
  case XML_BUFFER_ALLOC_IO:
656
0
  case XML_BUFFER_ALLOC_DOUBLEIT:
657
      /*take care of empty case*/
658
0
            if (buf->size == 0) {
659
0
                newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
660
0
            } else {
661
0
                newSize = buf->size;
662
0
            }
663
0
      while (size > newSize) {
664
0
          if (newSize > SIZE_MAX / 2) {
665
0
              xmlBufMemoryError(buf);
666
0
              return 0;
667
0
          }
668
0
          newSize *= 2;
669
0
      }
670
0
      break;
671
0
  case XML_BUFFER_ALLOC_EXACT:
672
0
            newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
673
0
      break;
674
0
        case XML_BUFFER_ALLOC_HYBRID:
675
0
            if (buf->use < BASE_BUFFER_SIZE)
676
0
                newSize = size;
677
0
            else {
678
0
                newSize = buf->size;
679
0
                while (size > newSize) {
680
0
                    if (newSize > SIZE_MAX / 2) {
681
0
                        xmlBufMemoryError(buf);
682
0
                        return 0;
683
0
                    }
684
0
                    newSize *= 2;
685
0
                }
686
0
            }
687
0
            break;
688
689
0
  default:
690
0
            newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
691
0
      break;
692
0
    }
693
694
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
695
0
        start_buf = buf->content - buf->contentIO;
696
697
0
        if (start_buf > newSize) {
698
      /* move data back to start */
699
0
      memmove(buf->contentIO, buf->content, buf->use);
700
0
      buf->content = buf->contentIO;
701
0
      buf->content[buf->use] = 0;
702
0
      buf->size += start_buf;
703
0
  } else {
704
0
      rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
705
0
      if (rebuf == NULL) {
706
0
    xmlBufMemoryError(buf);
707
0
    return 0;
708
0
      }
709
0
      buf->contentIO = rebuf;
710
0
      buf->content = rebuf + start_buf;
711
0
  }
712
0
    } else {
713
0
  if (buf->content == NULL) {
714
0
      rebuf = (xmlChar *) xmlMallocAtomic(newSize);
715
0
      buf->use = 0;
716
0
            if (rebuf != NULL)
717
0
          rebuf[buf->use] = 0;
718
0
  } else if (buf->size - buf->use < 100) {
719
0
      rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
720
0
        } else {
721
      /*
722
       * if we are reallocating a buffer far from being full, it's
723
       * better to make a new allocation and copy only the used range
724
       * and free the old one.
725
       */
726
0
      rebuf = (xmlChar *) xmlMallocAtomic(newSize);
727
0
      if (rebuf != NULL) {
728
0
    memcpy(rebuf, buf->content, buf->use);
729
0
    xmlFree(buf->content);
730
0
    rebuf[buf->use] = 0;
731
0
      }
732
0
  }
733
0
  if (rebuf == NULL) {
734
0
      xmlBufMemoryError(buf);
735
0
      return 0;
736
0
  }
737
0
  buf->content = rebuf;
738
0
    }
739
0
    buf->size = newSize;
740
0
    UPDATE_COMPAT(buf)
741
742
0
    return 1;
743
0
}
744
745
/**
746
 * xmlBufAdd:
747
 * @buf:  the buffer to dump
748
 * @str:  the #xmlChar string
749
 * @len:  the number of #xmlChar to add
750
 *
751
 * Add a string range to an XML buffer. if len == -1, the length of
752
 * str is recomputed.
753
 *
754
 * Returns 0 if successful, -1 in case of error.
755
 */
756
int
757
0
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
758
0
    size_t needSize;
759
760
0
    if ((str == NULL) || (buf == NULL) || (buf->error))
761
0
  return -1;
762
0
    CHECK_COMPAT(buf)
763
764
0
    if (len < -1) {
765
0
  return -1;
766
0
    }
767
0
    if (len == 0) return 0;
768
769
0
    if (len < 0)
770
0
        len = xmlStrlen(str);
771
772
0
    if (len < 0) return -1;
773
0
    if (len == 0) return 0;
774
775
    /* Note that both buf->size and buf->use can be zero here. */
776
0
    if ((size_t) len >= buf->size - buf->use) {
777
0
        if ((size_t) len >= SIZE_MAX - buf->use) {
778
0
            xmlBufMemoryError(buf);
779
0
            return(-1);
780
0
        }
781
0
        needSize = buf->use + len + 1;
782
0
  if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
783
      /*
784
       * Used to provide parsing limits
785
       */
786
0
      if (needSize >= XML_MAX_TEXT_LENGTH) {
787
0
    xmlBufMemoryError(buf);
788
0
    return(-1);
789
0
      }
790
0
  }
791
0
        if (!xmlBufResize(buf, needSize))
792
0
            return(-1);
793
0
    }
794
795
0
    memmove(&buf->content[buf->use], str, len);
796
0
    buf->use += len;
797
0
    buf->content[buf->use] = 0;
798
0
    UPDATE_COMPAT(buf)
799
0
    return 0;
800
0
}
801
802
/**
803
 * xmlBufCat:
804
 * @buf:  the buffer to add to
805
 * @str:  the #xmlChar string
806
 *
807
 * Append a zero terminated string to an XML buffer.
808
 *
809
 * Returns 0 successful, a positive error code number otherwise
810
 *         and -1 in case of internal or API error.
811
 */
812
int
813
0
xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
814
0
    if ((buf == NULL) || (buf->error))
815
0
        return(-1);
816
0
    CHECK_COMPAT(buf)
817
0
    if (str == NULL) return -1;
818
0
    return xmlBufAdd(buf, str, -1);
819
0
}
820
821
/**
822
 * xmlBufFromBuffer:
823
 * @buffer: incoming old buffer to convert to a new one
824
 *
825
 * Helper routine to switch from the old buffer structures in use
826
 * in various APIs. It creates a wrapper xmlBufPtr which will be
827
 * used for internal processing until the xmlBufBackToBuffer() is
828
 * issued.
829
 *
830
 * Returns a new xmlBufPtr unless the call failed and NULL is returned
831
 */
832
xmlBufPtr
833
0
xmlBufFromBuffer(xmlBufferPtr buffer) {
834
0
    xmlBufPtr ret;
835
836
0
    if (buffer == NULL)
837
0
        return(NULL);
838
839
0
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
840
0
    if (ret == NULL) {
841
0
        return(NULL);
842
0
    }
843
0
    ret->use = buffer->use;
844
0
    ret->size = buffer->size;
845
0
    UPDATE_COMPAT(ret);
846
0
    ret->error = 0;
847
0
    ret->buffer = buffer;
848
0
    ret->alloc = buffer->alloc;
849
0
    ret->content = buffer->content;
850
0
    ret->contentIO = buffer->contentIO;
851
852
0
    return(ret);
853
0
}
854
855
/**
856
 * xmlBufBackToBuffer:
857
 * @buf: new buffer wrapping the old one
858
 *
859
 * Function to be called once internal processing had been done to
860
 * update back the buffer provided by the user. This can lead to
861
 * a failure in case the size accumulated in the xmlBuf is larger
862
 * than what an xmlBuffer can support on 64 bits (INT_MAX)
863
 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
864
 *
865
 * Returns the old xmlBufferPtr unless the call failed and NULL is returned
866
 */
867
xmlBufferPtr
868
0
xmlBufBackToBuffer(xmlBufPtr buf) {
869
0
    xmlBufferPtr ret;
870
871
0
    if (buf == NULL)
872
0
        return(NULL);
873
0
    CHECK_COMPAT(buf)
874
0
    ret = buf->buffer;
875
876
0
    if ((buf->error) || (ret == NULL)) {
877
0
        xmlBufFree(buf);
878
0
        if (ret != NULL) {
879
0
            ret->content = NULL;
880
0
            ret->contentIO = NULL;
881
0
            ret->use = 0;
882
0
            ret->size = 0;
883
0
        }
884
0
        return(NULL);
885
0
    }
886
887
    /*
888
     * What to do in case of error in the buffer ???
889
     */
890
0
    if (buf->use > INT_MAX) {
891
        /*
892
         * Worse case, we really allocated and used more than the
893
         * maximum allowed memory for an xmlBuffer on this architecture.
894
         * Keep the buffer but provide a truncated size value.
895
         */
896
0
        xmlBufOverflowError(buf);
897
0
        ret->use = INT_MAX;
898
0
        ret->size = INT_MAX;
899
0
    } else if (buf->size > INT_MAX) {
900
        /*
901
         * milder case, we allocated more than the maximum allowed memory
902
         * for an xmlBuffer on this architecture, but used less than the
903
         * limit.
904
         * Keep the buffer but provide a truncated size value.
905
         */
906
0
        xmlBufOverflowError(buf);
907
0
        ret->use = buf->use;
908
0
        ret->size = INT_MAX;
909
0
    } else {
910
0
        ret->use = buf->use;
911
0
        ret->size = buf->size;
912
0
    }
913
0
    ret->alloc = buf->alloc;
914
0
    ret->content = buf->content;
915
0
    ret->contentIO = buf->contentIO;
916
0
    xmlFree(buf);
917
0
    return(ret);
918
0
}
919
920
/**
921
 * xmlBufResetInput:
922
 * @buf: an xmlBufPtr
923
 * @input: an xmlParserInputPtr
924
 *
925
 * Update the input to use the current set of pointers from the buffer.
926
 *
927
 * Returns -1 in case of error, 0 otherwise
928
 */
929
int
930
0
xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
931
0
    return(xmlBufUpdateInput(buf, input, 0));
932
0
}
933
934
/**
935
 * xmlBufUpdateInput:
936
 * @buf: an xmlBufPtr
937
 * @input: an xmlParserInputPtr
938
 * @pos: the cur value relative to the beginning of the buffer
939
 *
940
 * Update the input to use the base and cur relative to the buffer
941
 * after a possible reallocation of its content
942
 *
943
 * Returns -1 in case of error, 0 otherwise
944
 */
945
int
946
0
xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
947
0
    if ((buf == NULL) || (input == NULL))
948
0
        return(-1);
949
0
    CHECK_COMPAT(buf)
950
0
    input->base = buf->content;
951
0
    input->cur = input->base + pos;
952
0
    input->end = &buf->content[buf->use];
953
0
    return(0);
954
0
}
955