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