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