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