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 
42 struct _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  */
90 static void
xmlBufMemoryError(xmlBufPtr buf,const char * extra)91 xmlBufMemoryError(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  */
105 static void
xmlBufOverflowError(xmlBufPtr buf,const char * extra)106 xmlBufOverflowError(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  */
120 xmlBufPtr
xmlBufCreate(void)121 xmlBufCreate(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  */
154 xmlBufPtr
xmlBufCreateSize(size_t size)155 xmlBufCreateSize(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  */
194 xmlChar *
xmlBufDetach(xmlBufPtr buf)195 xmlBufDetach(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  */
229 xmlBufPtr
xmlBufCreateStatic(void * mem,size_t size)230 xmlBufCreateStatic(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  */
265 int
xmlBufGetAllocationScheme(xmlBufPtr buf)266 xmlBufGetAllocationScheme(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  */
286 int
xmlBufSetAllocationScheme(xmlBufPtr buf,xmlBufferAllocationScheme scheme)287 xmlBufSetAllocationScheme(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  */
326 void
xmlBufFree(xmlBufPtr buf)327 xmlBufFree(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  */
352 void
xmlBufEmpty(xmlBufPtr buf)353 xmlBufEmpty(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  */
385 size_t
xmlBufShrink(xmlBufPtr buf,size_t len)386 xmlBufShrink(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  */
434 static size_t
xmlBufGrowInternal(xmlBufPtr buf,size_t len)435 xmlBufGrowInternal(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  */
494 int
xmlBufGrow(xmlBufPtr buf,int len)495 xmlBufGrow(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  */
516 int
xmlBufInflate(xmlBufPtr buf,size_t len)517 xmlBufInflate(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  */
533 size_t
xmlBufDump(FILE * file,xmlBufPtr buf)534 xmlBufDump(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 
567 xmlChar *
xmlBufContent(const xmlBuf * buf)568 xmlBufContent(const xmlBuf *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 
585 xmlChar *
xmlBufEnd(xmlBufPtr buf)586 xmlBufEnd(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  */
606 int
xmlBufAddLen(xmlBufPtr buf,size_t len)607 xmlBufAddLen(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  */
631 int
xmlBufErase(xmlBufPtr buf,size_t len)632 xmlBufErase(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 
653 size_t
xmlBufLength(const xmlBufPtr buf)654 xmlBufLength(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 
672 size_t
xmlBufUse(const xmlBufPtr buf)673 xmlBufUse(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 
693 size_t
xmlBufAvail(const xmlBufPtr buf)694 xmlBufAvail(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  */
711 int
xmlBufIsEmpty(const xmlBufPtr buf)712 xmlBufIsEmpty(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  */
730 int
xmlBufResize(xmlBufPtr buf,size_t size)731 xmlBufResize(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  */
844 int
xmlBufAdd(xmlBufPtr buf,const xmlChar * str,int len)845 xmlBufAdd(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  */
895 int
xmlBufAddHead(xmlBufPtr buf,const xmlChar * str,int len)896 xmlBufAddHead(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  */
965 int
xmlBufCat(xmlBufPtr buf,const xmlChar * str)966 xmlBufCat(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  */
985 int
xmlBufCCat(xmlBufPtr buf,const char * str)986 xmlBufCCat(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  */
1025 int
xmlBufWriteCHAR(xmlBufPtr buf,const xmlChar * string)1026 xmlBufWriteCHAR(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  */
1046 int
xmlBufWriteChar(xmlBufPtr buf,const char * string)1047 xmlBufWriteChar(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  */
1069 int
xmlBufWriteQuotedString(xmlBufPtr buf,const xmlChar * string)1070 xmlBufWriteQuotedString(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  */
1125 xmlBufPtr
xmlBufFromBuffer(xmlBufferPtr buffer)1126 xmlBufFromBuffer(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  */
1162 xmlBufferPtr
xmlBufBackToBuffer(xmlBufPtr buf)1163 xmlBufBackToBuffer(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  */
1215 int
xmlBufMergeBuffer(xmlBufPtr buf,xmlBufferPtr buffer)1216 xmlBufMergeBuffer(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  */
1241 int
xmlBufResetInput(xmlBufPtr buf,xmlParserInputPtr input)1242 xmlBufResetInput(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  */
1260 size_t
xmlBufGetInputBase(xmlBufPtr buf,xmlParserInputPtr input)1261 xmlBufGetInputBase(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  */
1291 int
xmlBufSetInputBaseCur(xmlBufPtr buf,xmlParserInputPtr input,size_t base,size_t cur)1292 xmlBufSetInputBaseCur(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