Coverage Report

Created: 2024-08-17 10:59

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