Coverage Report

Created: 2022-05-03 06:10

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