Coverage Report

Created: 2025-08-04 07:15

/src/libxml2-2.9.7/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 maintainance
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
#ifdef HAVE_CTYPE_H
21
#include <ctype.h>
22
#endif
23
#ifdef HAVE_STDLIB_H
24
#include <stdlib.h>
25
#endif
26
27
#include <libxml/tree.h>
28
#include <libxml/globals.h>
29
#include <libxml/tree.h>
30
#include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
31
#include "buf.h"
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 informations
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 informations
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
0
xmlBufCreate(void) {
123
0
    xmlBufPtr ret;
124
125
0
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
126
0
    if (ret == NULL) {
127
0
  xmlBufMemoryError(NULL, "creating buffer");
128
0
        return(NULL);
129
0
    }
130
0
    ret->compat_use = 0;
131
0
    ret->use = 0;
132
0
    ret->error = 0;
133
0
    ret->buffer = NULL;
134
0
    ret->size = xmlDefaultBufferSize;
135
0
    ret->compat_size = xmlDefaultBufferSize;
136
0
    ret->alloc = xmlBufferAllocScheme;
137
0
    ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
138
0
    if (ret->content == NULL) {
139
0
  xmlBufMemoryError(ret, "creating buffer");
140
0
  xmlFree(ret);
141
0
        return(NULL);
142
0
    }
143
0
    ret->content[0] = 0;
144
0
    ret->contentIO = NULL;
145
0
    return(ret);
146
0
}
147
148
/**
149
 * xmlBufCreateSize:
150
 * @size: initial size of buffer
151
 *
152
 * routine to create an XML buffer.
153
 * returns the new structure.
154
 */
155
xmlBufPtr
156
0
xmlBufCreateSize(size_t size) {
157
0
    xmlBufPtr ret;
158
159
0
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
160
0
    if (ret == NULL) {
161
0
  xmlBufMemoryError(NULL, "creating buffer");
162
0
        return(NULL);
163
0
    }
164
0
    ret->compat_use = 0;
165
0
    ret->use = 0;
166
0
    ret->error = 0;
167
0
    ret->buffer = NULL;
168
0
    ret->alloc = xmlBufferAllocScheme;
169
0
    ret->size = (size ? size+2 : 0);         /* +1 for ending null */
170
0
    ret->compat_size = (int) ret->size;
171
0
    if (ret->size){
172
0
        ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
173
0
        if (ret->content == NULL) {
174
0
      xmlBufMemoryError(ret, "creating buffer");
175
0
            xmlFree(ret);
176
0
            return(NULL);
177
0
        }
178
0
        ret->content[0] = 0;
179
0
    } else
180
0
  ret->content = NULL;
181
0
    ret->contentIO = NULL;
182
0
    return(ret);
183
0
}
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
    buf->compat_use = 0;
213
0
    buf->compat_size = 0;
214
215
0
    return ret;
216
0
}
217
218
219
/**
220
 * xmlBufCreateStatic:
221
 * @mem: the memory area
222
 * @size:  the size in byte
223
 *
224
 * routine to create an XML buffer from an immutable memory area.
225
 * The area won't be modified nor copied, and is expected to be
226
 * present until the end of the buffer lifetime.
227
 *
228
 * returns the new structure.
229
 */
230
xmlBufPtr
231
0
xmlBufCreateStatic(void *mem, size_t size) {
232
0
    xmlBufPtr ret;
233
234
0
    if (mem == NULL)
235
0
        return(NULL);
236
237
0
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
238
0
    if (ret == NULL) {
239
0
  xmlBufMemoryError(NULL, "creating buffer");
240
0
        return(NULL);
241
0
    }
242
0
    if (size < INT_MAX) {
243
0
        ret->compat_use = size;
244
0
        ret->compat_size = size;
245
0
    } else {
246
0
        ret->compat_use = INT_MAX;
247
0
        ret->compat_size = INT_MAX;
248
0
    }
249
0
    ret->use = size;
250
0
    ret->size = size;
251
0
    ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
252
0
    ret->content = (xmlChar *) mem;
253
0
    ret->error = 0;
254
0
    ret->buffer = NULL;
255
0
    return(ret);
256
0
}
257
258
/**
259
 * xmlBufGetAllocationScheme:
260
 * @buf:  the buffer
261
 *
262
 * Get the buffer allocation scheme
263
 *
264
 * Returns the scheme or -1 in case of error
265
 */
266
int
267
0
xmlBufGetAllocationScheme(xmlBufPtr buf) {
268
0
    if (buf == NULL) {
269
#ifdef DEBUG_BUFFER
270
        xmlGenericError(xmlGenericErrorContext,
271
    "xmlBufGetAllocationScheme: buf == NULL\n");
272
#endif
273
0
        return(-1);
274
0
    }
275
0
    return(buf->alloc);
276
0
}
277
278
/**
279
 * xmlBufSetAllocationScheme:
280
 * @buf:  the buffer to tune
281
 * @scheme:  allocation scheme to use
282
 *
283
 * Sets the allocation scheme for this buffer
284
 *
285
 * returns 0 in case of success and -1 in case of failure
286
 */
287
int
288
xmlBufSetAllocationScheme(xmlBufPtr buf,
289
0
                          xmlBufferAllocationScheme scheme) {
290
0
    if ((buf == NULL) || (buf->error != 0)) {
291
#ifdef DEBUG_BUFFER
292
        xmlGenericError(xmlGenericErrorContext,
293
    "xmlBufSetAllocationScheme: buf == NULL or in error\n");
294
#endif
295
0
        return(-1);
296
0
    }
297
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
298
0
        (buf->alloc == XML_BUFFER_ALLOC_IO))
299
0
        return(-1);
300
0
    if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
301
0
        (scheme == XML_BUFFER_ALLOC_EXACT) ||
302
0
        (scheme == XML_BUFFER_ALLOC_HYBRID) ||
303
0
        (scheme == XML_BUFFER_ALLOC_IMMUTABLE) ||
304
0
  (scheme == XML_BUFFER_ALLOC_BOUNDED)) {
305
0
  buf->alloc = scheme;
306
0
        if (buf->buffer)
307
0
            buf->buffer->alloc = scheme;
308
0
        return(0);
309
0
    }
310
    /*
311
     * Switching a buffer ALLOC_IO has the side effect of initializing
312
     * the contentIO field with the current content
313
     */
314
0
    if (scheme == XML_BUFFER_ALLOC_IO) {
315
0
        buf->alloc = XML_BUFFER_ALLOC_IO;
316
0
        buf->contentIO = buf->content;
317
0
    }
318
0
    return(-1);
319
0
}
320
321
/**
322
 * xmlBufFree:
323
 * @buf:  the buffer to free
324
 *
325
 * Frees an XML buffer. It frees both the content and the structure which
326
 * encapsulate it.
327
 */
328
void
329
0
xmlBufFree(xmlBufPtr buf) {
330
0
    if (buf == NULL) {
331
#ifdef DEBUG_BUFFER
332
        xmlGenericError(xmlGenericErrorContext,
333
    "xmlBufFree: buf == NULL\n");
334
#endif
335
0
  return;
336
0
    }
337
338
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
339
0
        (buf->contentIO != NULL)) {
340
0
        xmlFree(buf->contentIO);
341
0
    } else if ((buf->content != NULL) &&
342
0
        (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
343
0
        xmlFree(buf->content);
344
0
    }
345
0
    xmlFree(buf);
346
0
}
347
348
/**
349
 * xmlBufEmpty:
350
 * @buf:  the buffer
351
 *
352
 * empty a buffer.
353
 */
354
void
355
0
xmlBufEmpty(xmlBufPtr buf) {
356
0
    if ((buf == NULL) || (buf->error != 0)) return;
357
0
    if (buf->content == NULL) return;
358
0
    CHECK_COMPAT(buf)
359
0
    buf->use = 0;
360
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
361
0
        buf->content = BAD_CAST "";
362
0
    } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
363
0
               (buf->contentIO != NULL)) {
364
0
        size_t start_buf = buf->content - buf->contentIO;
365
366
0
  buf->size += start_buf;
367
0
        buf->content = buf->contentIO;
368
0
        buf->content[0] = 0;
369
0
    } else {
370
0
        buf->content[0] = 0;
371
0
    }
372
0
    UPDATE_COMPAT(buf)
373
0
}
374
375
/**
376
 * xmlBufShrink:
377
 * @buf:  the buffer to dump
378
 * @len:  the number of xmlChar to remove
379
 *
380
 * Remove the beginning of an XML buffer.
381
 * NOTE that this routine behaviour differs from xmlBufferShrink()
382
 * as it will return 0 on error instead of -1 due to size_t being
383
 * used as the return type.
384
 *
385
 * Returns the number of byte removed or 0 in case of failure
386
 */
387
size_t
388
0
xmlBufShrink(xmlBufPtr buf, size_t len) {
389
0
    if ((buf == NULL) || (buf->error != 0)) return(0);
390
0
    CHECK_COMPAT(buf)
391
0
    if (len == 0) return(0);
392
0
    if (len > buf->use) return(0);
393
394
0
    buf->use -= len;
395
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
396
0
        ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
397
  /*
398
   * we just move the content pointer, but also make sure
399
   * the perceived buffer size has shrinked accordingly
400
   */
401
0
        buf->content += len;
402
0
  buf->size -= len;
403
404
        /*
405
   * sometimes though it maybe be better to really shrink
406
   * on IO buffers
407
   */
408
0
  if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
409
0
      size_t start_buf = buf->content - buf->contentIO;
410
0
      if (start_buf >= buf->size) {
411
0
    memmove(buf->contentIO, &buf->content[0], buf->use);
412
0
    buf->content = buf->contentIO;
413
0
    buf->content[buf->use] = 0;
414
0
    buf->size += start_buf;
415
0
      }
416
0
  }
417
0
    } else {
418
0
  memmove(buf->content, &buf->content[len], buf->use);
419
0
  buf->content[buf->use] = 0;
420
0
    }
421
0
    UPDATE_COMPAT(buf)
422
0
    return(len);
423
0
}
424
425
/**
426
 * xmlBufGrowInternal:
427
 * @buf:  the buffer
428
 * @len:  the minimum free size to allocate
429
 *
430
 * Grow the available space of an XML buffer, @len is the target value
431
 * Error checking should be done on buf->error since using the return
432
 * value doesn't work that well
433
 *
434
 * Returns 0 in case of error or the length made available otherwise
435
 */
436
static size_t
437
0
xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
438
0
    size_t size;
439
0
    xmlChar *newbuf;
440
441
0
    if ((buf == NULL) || (buf->error != 0)) return(0);
442
0
    CHECK_COMPAT(buf)
443
444
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
445
0
    if (buf->use + len < buf->size)
446
0
        return(buf->size - buf->use);
447
448
    /*
449
     * Windows has a BIG problem on realloc timing, so we try to double
450
     * the buffer size (if that's enough) (bug 146697)
451
     * Apparently BSD too, and it's probably best for linux too
452
     * On an embedded system this may be something to change
453
     */
454
0
#if 1
455
0
    if (buf->size > (size_t) len)
456
0
        size = buf->size * 2;
457
0
    else
458
0
        size = buf->use + len + 100;
459
#else
460
    size = buf->use + len + 100;
461
#endif
462
463
0
    if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
464
        /*
465
   * Used to provide parsing limits
466
   */
467
0
        if ((buf->use + len >= XML_MAX_TEXT_LENGTH) ||
468
0
      (buf->size >= XML_MAX_TEXT_LENGTH)) {
469
0
      xmlBufMemoryError(buf, "buffer error: text too long\n");
470
0
      return(0);
471
0
  }
472
0
  if (size >= XML_MAX_TEXT_LENGTH)
473
0
      size = XML_MAX_TEXT_LENGTH;
474
0
    }
475
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
476
0
        size_t start_buf = buf->content - buf->contentIO;
477
478
0
  newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
479
0
  if (newbuf == NULL) {
480
0
      xmlBufMemoryError(buf, "growing buffer");
481
0
      return(0);
482
0
  }
483
0
  buf->contentIO = newbuf;
484
0
  buf->content = newbuf + start_buf;
485
0
    } else {
486
0
  newbuf = (xmlChar *) xmlRealloc(buf->content, size);
487
0
  if (newbuf == NULL) {
488
0
      xmlBufMemoryError(buf, "growing buffer");
489
0
      return(0);
490
0
  }
491
0
  buf->content = newbuf;
492
0
    }
493
0
    buf->size = size;
494
0
    UPDATE_COMPAT(buf)
495
0
    return(buf->size - buf->use);
496
0
}
497
498
/**
499
 * xmlBufGrow:
500
 * @buf:  the buffer
501
 * @len:  the minimum free size to allocate
502
 *
503
 * Grow the available space of an XML buffer, @len is the target value
504
 * This is been kept compatible with xmlBufferGrow() as much as possible
505
 *
506
 * Returns -1 in case of error or the length made available otherwise
507
 */
508
int
509
0
xmlBufGrow(xmlBufPtr buf, int len) {
510
0
    size_t ret;
511
512
0
    if ((buf == NULL) || (len < 0)) return(-1);
513
0
    if (len == 0)
514
0
        return(0);
515
0
    ret = xmlBufGrowInternal(buf, len);
516
0
    if (buf->error != 0)
517
0
        return(-1);
518
0
    return((int) ret);
519
0
}
520
521
/**
522
 * xmlBufInflate:
523
 * @buf:  the buffer
524
 * @len:  the minimum extra free size to allocate
525
 *
526
 * Grow the available space of an XML buffer, adding at least @len bytes
527
 *
528
 * Returns 0 if successful or -1 in case of error
529
 */
530
int
531
0
xmlBufInflate(xmlBufPtr buf, size_t len) {
532
0
    if (buf == NULL) return(-1);
533
0
    xmlBufGrowInternal(buf, len + buf->size);
534
0
    if (buf->error)
535
0
        return(-1);
536
0
    return(0);
537
0
}
538
539
/**
540
 * xmlBufDump:
541
 * @file:  the file output
542
 * @buf:  the buffer to dump
543
 *
544
 * Dumps an XML buffer to  a FILE *.
545
 * Returns the number of #xmlChar written
546
 */
547
size_t
548
0
xmlBufDump(FILE *file, xmlBufPtr buf) {
549
0
    size_t ret;
550
551
0
    if ((buf == NULL) || (buf->error != 0)) {
552
#ifdef DEBUG_BUFFER
553
        xmlGenericError(xmlGenericErrorContext,
554
    "xmlBufDump: buf == NULL or in error\n");
555
#endif
556
0
  return(0);
557
0
    }
558
0
    if (buf->content == NULL) {
559
#ifdef DEBUG_BUFFER
560
        xmlGenericError(xmlGenericErrorContext,
561
    "xmlBufDump: buf->content == NULL\n");
562
#endif
563
0
  return(0);
564
0
    }
565
0
    CHECK_COMPAT(buf)
566
0
    if (file == NULL)
567
0
  file = stdout;
568
0
    ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
569
0
    return(ret);
570
0
}
571
572
/**
573
 * xmlBufContent:
574
 * @buf:  the buffer
575
 *
576
 * Function to extract the content of a buffer
577
 *
578
 * Returns the internal content
579
 */
580
581
xmlChar *
582
xmlBufContent(const xmlBuf *buf)
583
0
{
584
0
    if ((!buf) || (buf->error))
585
0
        return NULL;
586
587
0
    return(buf->content);
588
0
}
589
590
/**
591
 * xmlBufEnd:
592
 * @buf:  the buffer
593
 *
594
 * Function to extract the end of the content of a buffer
595
 *
596
 * Returns the end of the internal content or NULL in case of error
597
 */
598
599
xmlChar *
600
xmlBufEnd(xmlBufPtr buf)
601
0
{
602
0
    if ((!buf) || (buf->error))
603
0
        return NULL;
604
0
    CHECK_COMPAT(buf)
605
606
0
    return(&buf->content[buf->use]);
607
0
}
608
609
/**
610
 * xmlBufAddLen:
611
 * @buf:  the buffer
612
 * @len:  the size which were added at the end
613
 *
614
 * Sometime data may be added at the end of the buffer without
615
 * using the xmlBuf APIs that is used to expand the used space
616
 * and set the zero terminating at the end of the buffer
617
 *
618
 * Returns -1 in case of error and 0 otherwise
619
 */
620
int
621
0
xmlBufAddLen(xmlBufPtr buf, size_t len) {
622
0
    if ((buf == NULL) || (buf->error))
623
0
        return(-1);
624
0
    CHECK_COMPAT(buf)
625
0
    if (len > (buf->size - buf->use))
626
0
        return(-1);
627
0
    buf->use += len;
628
0
    UPDATE_COMPAT(buf)
629
0
    if (buf->size > buf->use)
630
0
        buf->content[buf->use] = 0;
631
0
    else
632
0
        return(-1);
633
0
    return(0);
634
0
}
635
636
/**
637
 * xmlBufErase:
638
 * @buf:  the buffer
639
 * @len:  the size to erase at the end
640
 *
641
 * Sometime data need to be erased at the end of the buffer
642
 *
643
 * Returns -1 in case of error and 0 otherwise
644
 */
645
int
646
0
xmlBufErase(xmlBufPtr buf, size_t len) {
647
0
    if ((buf == NULL) || (buf->error))
648
0
        return(-1);
649
0
    CHECK_COMPAT(buf)
650
0
    if (len > buf->use)
651
0
        return(-1);
652
0
    buf->use -= len;
653
0
    buf->content[buf->use] = 0;
654
0
    UPDATE_COMPAT(buf)
655
0
    return(0);
656
0
}
657
658
/**
659
 * xmlBufLength:
660
 * @buf:  the buffer
661
 *
662
 * Function to get the length of a buffer
663
 *
664
 * Returns the length of data in the internal content
665
 */
666
667
size_t
668
xmlBufLength(const xmlBufPtr buf)
669
0
{
670
0
    if ((!buf) || (buf->error))
671
0
        return 0;
672
0
    CHECK_COMPAT(buf)
673
674
0
    return(buf->use);
675
0
}
676
677
/**
678
 * xmlBufUse:
679
 * @buf:  the buffer
680
 *
681
 * Function to get the length of a buffer
682
 *
683
 * Returns the length of data in the internal content
684
 */
685
686
size_t
687
xmlBufUse(const xmlBufPtr buf)
688
0
{
689
0
    if ((!buf) || (buf->error))
690
0
        return 0;
691
0
    CHECK_COMPAT(buf)
692
693
0
    return(buf->use);
694
0
}
695
696
/**
697
 * xmlBufAvail:
698
 * @buf:  the buffer
699
 *
700
 * Function to find how much free space is allocated but not
701
 * used in the buffer. It does not account for the terminating zero
702
 * usually needed
703
 *
704
 * Returns the amount or 0 if none or an error occurred
705
 */
706
707
size_t
708
xmlBufAvail(const xmlBufPtr buf)
709
0
{
710
0
    if ((!buf) || (buf->error))
711
0
        return 0;
712
0
    CHECK_COMPAT(buf)
713
714
0
    return(buf->size - buf->use);
715
0
}
716
717
/**
718
 * xmlBufIsEmpty:
719
 * @buf:  the buffer
720
 *
721
 * Tell if a buffer is empty
722
 *
723
 * Returns 0 if no, 1 if yes and -1 in case of error
724
 */
725
int
726
xmlBufIsEmpty(const xmlBufPtr buf)
727
0
{
728
0
    if ((!buf) || (buf->error))
729
0
        return(-1);
730
0
    CHECK_COMPAT(buf)
731
732
0
    return(buf->use == 0);
733
0
}
734
735
/**
736
 * xmlBufResize:
737
 * @buf:  the buffer to resize
738
 * @size:  the desired size
739
 *
740
 * Resize a buffer to accommodate minimum size of @size.
741
 *
742
 * Returns  0 in case of problems, 1 otherwise
743
 */
744
int
745
xmlBufResize(xmlBufPtr buf, size_t size)
746
0
{
747
0
    unsigned int newSize;
748
0
    xmlChar* rebuf = NULL;
749
0
    size_t start_buf;
750
751
0
    if ((buf == NULL) || (buf->error))
752
0
        return(0);
753
0
    CHECK_COMPAT(buf)
754
755
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
756
0
    if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
757
        /*
758
   * Used to provide parsing limits
759
   */
760
0
        if (size >= XML_MAX_TEXT_LENGTH) {
761
0
      xmlBufMemoryError(buf, "buffer error: text too long\n");
762
0
      return(0);
763
0
  }
764
0
    }
765
766
    /* Don't resize if we don't have to */
767
0
    if (size < buf->size)
768
0
        return 1;
769
770
    /* figure out new size */
771
0
    switch (buf->alloc){
772
0
  case XML_BUFFER_ALLOC_IO:
773
0
  case XML_BUFFER_ALLOC_DOUBLEIT:
774
      /*take care of empty case*/
775
0
      newSize = (buf->size ? buf->size*2 : size + 10);
776
0
      while (size > newSize) {
777
0
          if (newSize > UINT_MAX / 2) {
778
0
              xmlBufMemoryError(buf, "growing buffer");
779
0
              return 0;
780
0
          }
781
0
          newSize *= 2;
782
0
      }
783
0
      break;
784
0
  case XML_BUFFER_ALLOC_EXACT:
785
0
      newSize = size+10;
786
0
      break;
787
0
        case XML_BUFFER_ALLOC_HYBRID:
788
0
            if (buf->use < BASE_BUFFER_SIZE)
789
0
                newSize = size;
790
0
            else {
791
0
                newSize = buf->size * 2;
792
0
                while (size > newSize) {
793
0
                    if (newSize > UINT_MAX / 2) {
794
0
                        xmlBufMemoryError(buf, "growing buffer");
795
0
                        return 0;
796
0
                    }
797
0
                    newSize *= 2;
798
0
                }
799
0
            }
800
0
            break;
801
802
0
  default:
803
0
      newSize = size+10;
804
0
      break;
805
0
    }
806
807
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
808
0
        start_buf = buf->content - buf->contentIO;
809
810
0
        if (start_buf > newSize) {
811
      /* move data back to start */
812
0
      memmove(buf->contentIO, buf->content, buf->use);
813
0
      buf->content = buf->contentIO;
814
0
      buf->content[buf->use] = 0;
815
0
      buf->size += start_buf;
816
0
  } else {
817
0
      rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
818
0
      if (rebuf == NULL) {
819
0
    xmlBufMemoryError(buf, "growing buffer");
820
0
    return 0;
821
0
      }
822
0
      buf->contentIO = rebuf;
823
0
      buf->content = rebuf + start_buf;
824
0
  }
825
0
    } else {
826
0
  if (buf->content == NULL) {
827
0
      rebuf = (xmlChar *) xmlMallocAtomic(newSize);
828
0
  } else if (buf->size - buf->use < 100) {
829
0
      rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
830
0
        } else {
831
      /*
832
       * if we are reallocating a buffer far from being full, it's
833
       * better to make a new allocation and copy only the used range
834
       * and free the old one.
835
       */
836
0
      rebuf = (xmlChar *) xmlMallocAtomic(newSize);
837
0
      if (rebuf != NULL) {
838
0
    memcpy(rebuf, buf->content, buf->use);
839
0
    xmlFree(buf->content);
840
0
    rebuf[buf->use] = 0;
841
0
      }
842
0
  }
843
0
  if (rebuf == NULL) {
844
0
      xmlBufMemoryError(buf, "growing buffer");
845
0
      return 0;
846
0
  }
847
0
  buf->content = rebuf;
848
0
    }
849
0
    buf->size = newSize;
850
0
    UPDATE_COMPAT(buf)
851
852
0
    return 1;
853
0
}
854
855
/**
856
 * xmlBufAdd:
857
 * @buf:  the buffer to dump
858
 * @str:  the #xmlChar string
859
 * @len:  the number of #xmlChar to add
860
 *
861
 * Add a string range to an XML buffer. if len == -1, the length of
862
 * str is recomputed.
863
 *
864
 * Returns 0 successful, a positive error code number otherwise
865
 *         and -1 in case of internal or API error.
866
 */
867
int
868
0
xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
869
0
    unsigned int needSize;
870
871
0
    if ((str == NULL) || (buf == NULL) || (buf->error))
872
0
  return -1;
873
0
    CHECK_COMPAT(buf)
874
875
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
876
0
    if (len < -1) {
877
#ifdef DEBUG_BUFFER
878
        xmlGenericError(xmlGenericErrorContext,
879
    "xmlBufAdd: len < 0\n");
880
#endif
881
0
  return -1;
882
0
    }
883
0
    if (len == 0) return 0;
884
885
0
    if (len < 0)
886
0
        len = xmlStrlen(str);
887
888
0
    if (len < 0) return -1;
889
0
    if (len == 0) return 0;
890
891
0
    needSize = buf->use + len + 2;
892
0
    if (needSize > buf->size){
893
0
  if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
894
      /*
895
       * Used to provide parsing limits
896
       */
897
0
      if (needSize >= XML_MAX_TEXT_LENGTH) {
898
0
    xmlBufMemoryError(buf, "buffer error: text too long\n");
899
0
    return(-1);
900
0
      }
901
0
  }
902
0
        if (!xmlBufResize(buf, needSize)){
903
0
      xmlBufMemoryError(buf, "growing buffer");
904
0
            return XML_ERR_NO_MEMORY;
905
0
        }
906
0
    }
907
908
0
    memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
909
0
    buf->use += len;
910
0
    buf->content[buf->use] = 0;
911
0
    UPDATE_COMPAT(buf)
912
0
    return 0;
913
0
}
914
915
/**
916
 * xmlBufAddHead:
917
 * @buf:  the buffer
918
 * @str:  the #xmlChar string
919
 * @len:  the number of #xmlChar to add
920
 *
921
 * Add a string range to the beginning of an XML buffer.
922
 * if len == -1, the length of @str is recomputed.
923
 *
924
 * Returns 0 successful, a positive error code number otherwise
925
 *         and -1 in case of internal or API error.
926
 */
927
int
928
0
xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
929
0
    unsigned int needSize;
930
931
0
    if ((buf == NULL) || (buf->error))
932
0
        return(-1);
933
0
    CHECK_COMPAT(buf)
934
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
935
0
    if (str == NULL) {
936
#ifdef DEBUG_BUFFER
937
        xmlGenericError(xmlGenericErrorContext,
938
    "xmlBufAddHead: str == NULL\n");
939
#endif
940
0
  return -1;
941
0
    }
942
0
    if (len < -1) {
943
#ifdef DEBUG_BUFFER
944
        xmlGenericError(xmlGenericErrorContext,
945
    "xmlBufAddHead: len < 0\n");
946
#endif
947
0
  return -1;
948
0
    }
949
0
    if (len == 0) return 0;
950
951
0
    if (len < 0)
952
0
        len = xmlStrlen(str);
953
954
0
    if (len <= 0) return -1;
955
956
0
    if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
957
0
        size_t start_buf = buf->content - buf->contentIO;
958
959
0
  if (start_buf > (unsigned int) len) {
960
      /*
961
       * We can add it in the space previously shrinked
962
       */
963
0
      buf->content -= len;
964
0
            memmove(&buf->content[0], str, len);
965
0
      buf->use += len;
966
0
      buf->size += len;
967
0
      UPDATE_COMPAT(buf)
968
0
      return(0);
969
0
  }
970
0
    }
971
0
    needSize = buf->use + len + 2;
972
0
    if (needSize > buf->size){
973
0
  if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
974
      /*
975
       * Used to provide parsing limits
976
       */
977
0
      if (needSize >= XML_MAX_TEXT_LENGTH) {
978
0
    xmlBufMemoryError(buf, "buffer error: text too long\n");
979
0
    return(-1);
980
0
      }
981
0
  }
982
0
        if (!xmlBufResize(buf, needSize)){
983
0
      xmlBufMemoryError(buf, "growing buffer");
984
0
            return XML_ERR_NO_MEMORY;
985
0
        }
986
0
    }
987
988
0
    memmove(&buf->content[len], &buf->content[0], buf->use);
989
0
    memmove(&buf->content[0], str, len);
990
0
    buf->use += len;
991
0
    buf->content[buf->use] = 0;
992
0
    UPDATE_COMPAT(buf)
993
0
    return 0;
994
0
}
995
996
/**
997
 * xmlBufCat:
998
 * @buf:  the buffer to add to
999
 * @str:  the #xmlChar string
1000
 *
1001
 * Append a zero terminated string to an XML buffer.
1002
 *
1003
 * Returns 0 successful, a positive error code number otherwise
1004
 *         and -1 in case of internal or API error.
1005
 */
1006
int
1007
0
xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
1008
0
    if ((buf == NULL) || (buf->error))
1009
0
        return(-1);
1010
0
    CHECK_COMPAT(buf)
1011
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1012
0
    if (str == NULL) return -1;
1013
0
    return xmlBufAdd(buf, str, -1);
1014
0
}
1015
1016
/**
1017
 * xmlBufCCat:
1018
 * @buf:  the buffer to dump
1019
 * @str:  the C char string
1020
 *
1021
 * Append a zero terminated C string to an XML buffer.
1022
 *
1023
 * Returns 0 successful, a positive error code number otherwise
1024
 *         and -1 in case of internal or API error.
1025
 */
1026
int
1027
0
xmlBufCCat(xmlBufPtr buf, const char *str) {
1028
0
    const char *cur;
1029
1030
0
    if ((buf == NULL) || (buf->error))
1031
0
        return(-1);
1032
0
    CHECK_COMPAT(buf)
1033
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1034
0
    if (str == NULL) {
1035
#ifdef DEBUG_BUFFER
1036
        xmlGenericError(xmlGenericErrorContext,
1037
    "xmlBufCCat: str == NULL\n");
1038
#endif
1039
0
  return -1;
1040
0
    }
1041
0
    for (cur = str;*cur != 0;cur++) {
1042
0
        if (buf->use  + 10 >= buf->size) {
1043
0
            if (!xmlBufResize(buf, buf->use+10)){
1044
0
    xmlBufMemoryError(buf, "growing buffer");
1045
0
                return XML_ERR_NO_MEMORY;
1046
0
            }
1047
0
        }
1048
0
        buf->content[buf->use++] = *cur;
1049
0
    }
1050
0
    buf->content[buf->use] = 0;
1051
0
    UPDATE_COMPAT(buf)
1052
0
    return 0;
1053
0
}
1054
1055
/**
1056
 * xmlBufWriteCHAR:
1057
 * @buf:  the XML buffer
1058
 * @string:  the string to add
1059
 *
1060
 * routine which manages and grows an output buffer. This one adds
1061
 * xmlChars at the end of the buffer.
1062
 *
1063
 * Returns 0 if successful, a positive error code number otherwise
1064
 *         and -1 in case of internal or API error.
1065
 */
1066
int
1067
0
xmlBufWriteCHAR(xmlBufPtr buf, const xmlChar *string) {
1068
0
    if ((buf == NULL) || (buf->error))
1069
0
        return(-1);
1070
0
    CHECK_COMPAT(buf)
1071
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1072
0
        return(-1);
1073
0
    return(xmlBufCat(buf, string));
1074
0
}
1075
1076
/**
1077
 * xmlBufWriteChar:
1078
 * @buf:  the XML buffer output
1079
 * @string:  the string to add
1080
 *
1081
 * routine which manage and grows an output buffer. This one add
1082
 * C chars at the end of the array.
1083
 *
1084
 * Returns 0 if successful, a positive error code number otherwise
1085
 *         and -1 in case of internal or API error.
1086
 */
1087
int
1088
0
xmlBufWriteChar(xmlBufPtr buf, const char *string) {
1089
0
    if ((buf == NULL) || (buf->error))
1090
0
        return(-1);
1091
0
    CHECK_COMPAT(buf)
1092
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1093
0
        return(-1);
1094
0
    return(xmlBufCCat(buf, string));
1095
0
}
1096
1097
1098
/**
1099
 * xmlBufWriteQuotedString:
1100
 * @buf:  the XML buffer output
1101
 * @string:  the string to add
1102
 *
1103
 * routine which manage and grows an output buffer. This one writes
1104
 * a quoted or double quoted #xmlChar string, checking first if it holds
1105
 * quote or double-quotes internally
1106
 *
1107
 * Returns 0 if successful, a positive error code number otherwise
1108
 *         and -1 in case of internal or API error.
1109
 */
1110
int
1111
0
xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
1112
0
    const xmlChar *cur, *base;
1113
0
    if ((buf == NULL) || (buf->error))
1114
0
        return(-1);
1115
0
    CHECK_COMPAT(buf)
1116
0
    if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1117
0
        return(-1);
1118
0
    if (xmlStrchr(string, '\"')) {
1119
0
        if (xmlStrchr(string, '\'')) {
1120
#ifdef DEBUG_BUFFER
1121
      xmlGenericError(xmlGenericErrorContext,
1122
 "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
1123
#endif
1124
0
      xmlBufCCat(buf, "\"");
1125
0
            base = cur = string;
1126
0
            while(*cur != 0){
1127
0
                if(*cur == '"'){
1128
0
                    if (base != cur)
1129
0
                        xmlBufAdd(buf, base, cur - base);
1130
0
                    xmlBufAdd(buf, BAD_CAST "&quot;", 6);
1131
0
                    cur++;
1132
0
                    base = cur;
1133
0
                }
1134
0
                else {
1135
0
                    cur++;
1136
0
                }
1137
0
            }
1138
0
            if (base != cur)
1139
0
                xmlBufAdd(buf, base, cur - base);
1140
0
      xmlBufCCat(buf, "\"");
1141
0
  }
1142
0
        else{
1143
0
      xmlBufCCat(buf, "\'");
1144
0
            xmlBufCat(buf, string);
1145
0
      xmlBufCCat(buf, "\'");
1146
0
        }
1147
0
    } else {
1148
0
        xmlBufCCat(buf, "\"");
1149
0
        xmlBufCat(buf, string);
1150
0
        xmlBufCCat(buf, "\"");
1151
0
    }
1152
0
    return(0);
1153
0
}
1154
1155
/**
1156
 * xmlBufFromBuffer:
1157
 * @buffer: incoming old buffer to convert to a new one
1158
 *
1159
 * Helper routine to switch from the old buffer structures in use
1160
 * in various APIs. It creates a wrapper xmlBufPtr which will be
1161
 * used for internal processing until the xmlBufBackToBuffer() is
1162
 * issued.
1163
 *
1164
 * Returns a new xmlBufPtr unless the call failed and NULL is returned
1165
 */
1166
xmlBufPtr
1167
0
xmlBufFromBuffer(xmlBufferPtr buffer) {
1168
0
    xmlBufPtr ret;
1169
1170
0
    if (buffer == NULL)
1171
0
        return(NULL);
1172
1173
0
    ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
1174
0
    if (ret == NULL) {
1175
0
  xmlBufMemoryError(NULL, "creating buffer");
1176
0
        return(NULL);
1177
0
    }
1178
0
    ret->use = buffer->use;
1179
0
    ret->size = buffer->size;
1180
0
    ret->compat_use = buffer->use;
1181
0
    ret->compat_size = buffer->size;
1182
0
    ret->error = 0;
1183
0
    ret->buffer = buffer;
1184
0
    ret->alloc = buffer->alloc;
1185
0
    ret->content = buffer->content;
1186
0
    ret->contentIO = buffer->contentIO;
1187
1188
0
    return(ret);
1189
0
}
1190
1191
/**
1192
 * xmlBufBackToBuffer:
1193
 * @buf: new buffer wrapping the old one
1194
 *
1195
 * Function to be called once internal processing had been done to
1196
 * update back the buffer provided by the user. This can lead to
1197
 * a failure in case the size accumulated in the xmlBuf is larger
1198
 * than what an xmlBuffer can support on 64 bits (INT_MAX)
1199
 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
1200
 *
1201
 * Returns the old xmlBufferPtr unless the call failed and NULL is returned
1202
 */
1203
xmlBufferPtr
1204
0
xmlBufBackToBuffer(xmlBufPtr buf) {
1205
0
    xmlBufferPtr ret;
1206
1207
0
    if ((buf == NULL) || (buf->error))
1208
0
        return(NULL);
1209
0
    CHECK_COMPAT(buf)
1210
0
    if (buf->buffer == NULL) {
1211
0
        xmlBufFree(buf);
1212
0
        return(NULL);
1213
0
    }
1214
1215
0
    ret = buf->buffer;
1216
    /*
1217
     * What to do in case of error in the buffer ???
1218
     */
1219
0
    if (buf->use > INT_MAX) {
1220
        /*
1221
         * Worse case, we really allocated and used more than the
1222
         * maximum allowed memory for an xmlBuffer on this architecture.
1223
         * Keep the buffer but provide a truncated size value.
1224
         */
1225
0
        xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
1226
0
        ret->use = INT_MAX;
1227
0
        ret->size = INT_MAX;
1228
0
    } else if (buf->size > INT_MAX) {
1229
        /*
1230
         * milder case, we allocated more than the maximum allowed memory
1231
         * for an xmlBuffer on this architecture, but used less than the
1232
         * limit.
1233
         * Keep the buffer but provide a truncated size value.
1234
         */
1235
0
        xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
1236
0
        ret->size = INT_MAX;
1237
0
    }
1238
0
    ret->use = (int) buf->use;
1239
0
    ret->size = (int) buf->size;
1240
0
    ret->alloc = buf->alloc;
1241
0
    ret->content = buf->content;
1242
0
    ret->contentIO = buf->contentIO;
1243
0
    xmlFree(buf);
1244
0
    return(ret);
1245
0
}
1246
1247
/**
1248
 * xmlBufMergeBuffer:
1249
 * @buf: an xmlBufPtr
1250
 * @buffer: the buffer to consume into @buf
1251
 *
1252
 * The content of @buffer is appended to @buf and @buffer is freed
1253
 *
1254
 * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
1255
 */
1256
int
1257
0
xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
1258
0
    int ret = 0;
1259
1260
0
    if ((buf == NULL) || (buf->error)) {
1261
0
  xmlBufferFree(buffer);
1262
0
        return(-1);
1263
0
    }
1264
0
    CHECK_COMPAT(buf)
1265
0
    if ((buffer != NULL) && (buffer->content != NULL) &&
1266
0
             (buffer->use > 0)) {
1267
0
        ret = xmlBufAdd(buf, buffer->content, buffer->use);
1268
0
    }
1269
0
    xmlBufferFree(buffer);
1270
0
    return(ret);
1271
0
}
1272
1273
/**
1274
 * xmlBufResetInput:
1275
 * @buf: an xmlBufPtr
1276
 * @input: an xmlParserInputPtr
1277
 *
1278
 * Update the input to use the current set of pointers from the buffer.
1279
 *
1280
 * Returns -1 in case of error, 0 otherwise
1281
 */
1282
int
1283
0
xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
1284
0
    if ((input == NULL) || (buf == NULL) || (buf->error))
1285
0
        return(-1);
1286
0
    CHECK_COMPAT(buf)
1287
0
    input->base = input->cur = buf->content;
1288
0
    input->end = &buf->content[buf->use];
1289
0
    return(0);
1290
0
}
1291
1292
/**
1293
 * xmlBufGetInputBase:
1294
 * @buf: an xmlBufPtr
1295
 * @input: an xmlParserInputPtr
1296
 *
1297
 * Get the base of the @input relative to the beginning of the buffer
1298
 *
1299
 * Returns the size_t corresponding to the displacement
1300
 */
1301
size_t
1302
0
xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
1303
0
    size_t base;
1304
1305
0
    if ((input == NULL) || (buf == NULL) || (buf->error))
1306
0
        return(-1);
1307
0
    CHECK_COMPAT(buf)
1308
0
    base = input->base - buf->content;
1309
    /*
1310
     * We could do some pointer arythmetic checks but that's probably
1311
     * sufficient.
1312
     */
1313
0
    if (base > buf->size) {
1314
0
        xmlBufOverflowError(buf, "Input reference outside of the buffer");
1315
0
        base = 0;
1316
0
    }
1317
0
    return(base);
1318
0
}
1319
1320
/**
1321
 * xmlBufSetInputBaseCur:
1322
 * @buf: an xmlBufPtr
1323
 * @input: an xmlParserInputPtr
1324
 * @base: the base value relative to the beginning of the buffer
1325
 * @cur: the cur value relative to the beginning of the buffer
1326
 *
1327
 * Update the input to use the base and cur relative to the buffer
1328
 * after a possible reallocation of its content
1329
 *
1330
 * Returns -1 in case of error, 0 otherwise
1331
 */
1332
int
1333
xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
1334
0
                      size_t base, size_t cur) {
1335
0
    if ((input == NULL) || (buf == NULL) || (buf->error))
1336
0
        return(-1);
1337
0
    CHECK_COMPAT(buf)
1338
0
    input->base = &buf->content[base];
1339
0
    input->cur = input->base + cur;
1340
0
    input->end = &buf->content[buf->use];
1341
0
    return(0);
1342
0
}
1343
1344
#define bottom_buf
1345
#include "elfgcchack.h"