Coverage Report

Created: 2023-06-07 06:05

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