• 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 #include <ctype.h>
21 #include <stdlib.h>
22 
23 #include <libxml/tree.h>
24 #include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
25 
26 #include "private/buf.h"
27 #include "private/error.h"
28 
29 #ifndef SIZE_MAX
30 #define SIZE_MAX ((size_t) -1)
31 #endif
32 
33 #define WITH_BUFFER_COMPAT
34 
35 /**
36  * xmlBuf:
37  *
38  * A buffer structure. The base of the structure is somehow compatible
39  * with struct _xmlBuffer to limit risks on application which accessed
40  * directly the input->buf->buffer structures.
41  */
42 
43 struct _xmlBuf {
44     xmlChar *content;		/* The buffer content UTF8 */
45     unsigned int compat_use;    /* for binary compatibility */
46     unsigned int compat_size;   /* for binary compatibility */
47     xmlBufferAllocationScheme alloc; /* The realloc method */
48     xmlChar *contentIO;		/* in IO mode we may have a different base */
49     size_t use;		        /* The buffer size used */
50     size_t size;		/* The buffer size */
51     xmlBufferPtr buffer;        /* wrapper for an old buffer */
52     int error;                  /* an error code if a failure occurred */
53 };
54 
55 #ifdef WITH_BUFFER_COMPAT
56 /*
57  * Macro for compatibility with xmlBuffer to be used after an xmlBuf
58  * is updated. This makes sure the compat fields are updated too.
59  */
60 #define UPDATE_COMPAT(buf)				    \
61      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 information
87  *
88  * Handle an out of memory condition
89  * To be improved...
90  */
91 static void
xmlBufMemoryError(xmlBufPtr buf)92 xmlBufMemoryError(xmlBufPtr buf)
93 {
94     if (buf->error == 0)
95         buf->error = XML_ERR_NO_MEMORY;
96 }
97 
98 /**
99  * xmlBufOverflowError:
100  * @extra:  extra information
101  *
102  * Handle a buffer overflow error
103  * To be improved...
104  */
105 static void
xmlBufOverflowError(xmlBufPtr buf)106 xmlBufOverflowError(xmlBufPtr buf)
107 {
108     if (buf->error == 0)
109         buf->error = XML_BUF_OVERFLOW;
110 }
111 
112 
113 /**
114  * xmlBufCreate:
115  *
116  * routine to create an XML buffer.
117  * returns the new structure.
118  */
119 xmlBufPtr
xmlBufCreate(void)120 xmlBufCreate(void) {
121     xmlBufPtr ret;
122 
123     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
124     if (ret == NULL)
125         return(NULL);
126     ret->use = 0;
127     ret->error = 0;
128     ret->buffer = NULL;
129     ret->size = xmlDefaultBufferSize;
130     UPDATE_COMPAT(ret);
131     ret->alloc = xmlBufferAllocScheme;
132     ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
133     if (ret->content == NULL) {
134 	xmlFree(ret);
135         return(NULL);
136     }
137     ret->content[0] = 0;
138     ret->contentIO = NULL;
139     return(ret);
140 }
141 
142 /**
143  * xmlBufCreateSize:
144  * @size: initial size of buffer
145  *
146  * routine to create an XML buffer.
147  * returns the new structure.
148  */
149 xmlBufPtr
xmlBufCreateSize(size_t size)150 xmlBufCreateSize(size_t size) {
151     xmlBufPtr ret;
152 
153     if (size == SIZE_MAX)
154         return(NULL);
155     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
156     if (ret == NULL)
157         return(NULL);
158     ret->use = 0;
159     ret->error = 0;
160     ret->buffer = NULL;
161     ret->alloc = xmlBufferAllocScheme;
162     ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
163     UPDATE_COMPAT(ret);
164     if (ret->size){
165         ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
166         if (ret->content == NULL) {
167             xmlFree(ret);
168             return(NULL);
169         }
170         ret->content[0] = 0;
171     } else
172 	ret->content = NULL;
173     ret->contentIO = NULL;
174     return(ret);
175 }
176 
177 /**
178  * xmlBufDetach:
179  * @buf:  the buffer
180  *
181  * Remove the string contained in a buffer and give it back to the
182  * caller. The buffer is reset to an empty content.
183  * This doesn't work with immutable buffers as they can't be reset.
184  *
185  * Returns the previous string contained by the buffer.
186  */
187 xmlChar *
xmlBufDetach(xmlBufPtr buf)188 xmlBufDetach(xmlBufPtr buf) {
189     xmlChar *ret;
190 
191     if (buf == NULL)
192         return(NULL);
193     if (buf->buffer != NULL)
194         return(NULL);
195     if (buf->error)
196         return(NULL);
197 
198     if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
199         (buf->content != buf->contentIO)) {
200         ret = xmlStrndup(buf->content, buf->use);
201         xmlFree(buf->contentIO);
202     } else {
203         ret = buf->content;
204     }
205 
206     buf->content = NULL;
207     buf->contentIO = NULL;
208     buf->size = 0;
209     buf->use = 0;
210     UPDATE_COMPAT(buf);
211 
212     return ret;
213 }
214 
215 /**
216  * xmlBufGetAllocationScheme:
217  * @buf:  the buffer
218  *
219  * Get the buffer allocation scheme
220  *
221  * Returns the scheme or -1 in case of error
222  */
223 int
xmlBufGetAllocationScheme(xmlBufPtr buf)224 xmlBufGetAllocationScheme(xmlBufPtr buf) {
225     if (buf == NULL) {
226         return(-1);
227     }
228     return(buf->alloc);
229 }
230 
231 /**
232  * xmlBufSetAllocationScheme:
233  * @buf:  the buffer to tune
234  * @scheme:  allocation scheme to use
235  *
236  * Sets the allocation scheme for this buffer
237  *
238  * returns 0 in case of success and -1 in case of failure
239  */
240 int
xmlBufSetAllocationScheme(xmlBufPtr buf,xmlBufferAllocationScheme scheme)241 xmlBufSetAllocationScheme(xmlBufPtr buf,
242                           xmlBufferAllocationScheme scheme) {
243     if ((buf == NULL) || (buf->error != 0)) {
244         return(-1);
245     }
246     if (buf->alloc == XML_BUFFER_ALLOC_IO)
247         return(-1);
248     if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
249         (scheme == XML_BUFFER_ALLOC_EXACT) ||
250         (scheme == XML_BUFFER_ALLOC_HYBRID) ||
251 	(scheme == XML_BUFFER_ALLOC_BOUNDED)) {
252 	buf->alloc = scheme;
253         if (buf->buffer)
254             buf->buffer->alloc = scheme;
255         return(0);
256     }
257     /*
258      * Switching a buffer ALLOC_IO has the side effect of initializing
259      * the contentIO field with the current content
260      */
261     if (scheme == XML_BUFFER_ALLOC_IO) {
262         buf->alloc = XML_BUFFER_ALLOC_IO;
263         buf->contentIO = buf->content;
264     }
265     return(-1);
266 }
267 
268 /**
269  * xmlBufFree:
270  * @buf:  the buffer to free
271  *
272  * Frees an XML buffer. It frees both the content and the structure which
273  * encapsulate it.
274  */
275 void
xmlBufFree(xmlBufPtr buf)276 xmlBufFree(xmlBufPtr buf) {
277     if (buf == NULL) {
278 	return;
279     }
280 
281     if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
282         (buf->contentIO != NULL)) {
283         xmlFree(buf->contentIO);
284     } else if (buf->content != NULL) {
285         xmlFree(buf->content);
286     }
287     xmlFree(buf);
288 }
289 
290 /**
291  * xmlBufEmpty:
292  * @buf:  the buffer
293  *
294  * empty a buffer.
295  */
296 void
xmlBufEmpty(xmlBufPtr buf)297 xmlBufEmpty(xmlBufPtr buf) {
298     if ((buf == NULL) || (buf->error != 0)) return;
299     if (buf->content == NULL) return;
300     CHECK_COMPAT(buf)
301     buf->use = 0;
302     if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
303                (buf->contentIO != NULL)) {
304         size_t start_buf = buf->content - buf->contentIO;
305 
306 	buf->size += start_buf;
307         buf->content = buf->contentIO;
308         buf->content[0] = 0;
309     } else {
310         buf->content[0] = 0;
311     }
312     UPDATE_COMPAT(buf)
313 }
314 
315 /**
316  * xmlBufShrink:
317  * @buf:  the buffer to dump
318  * @len:  the number of xmlChar to remove
319  *
320  * Remove the beginning of an XML buffer.
321  * NOTE that this routine behaviour differs from xmlBufferShrink()
322  * as it will return 0 on error instead of -1 due to size_t being
323  * used as the return type.
324  *
325  * Returns the number of byte removed or 0 in case of failure
326  */
327 size_t
xmlBufShrink(xmlBufPtr buf,size_t len)328 xmlBufShrink(xmlBufPtr buf, size_t len) {
329     if ((buf == NULL) || (buf->error != 0)) return(0);
330     CHECK_COMPAT(buf)
331     if (len == 0) return(0);
332     if (len > buf->use) return(0);
333 
334     buf->use -= len;
335     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
336 	/*
337 	 * we just move the content pointer, but also make sure
338 	 * the perceived buffer size has shrunk accordingly
339 	 */
340         buf->content += len;
341 	buf->size -= len;
342 
343         /*
344 	 * sometimes though it maybe be better to really shrink
345 	 * on IO buffers
346 	 */
347 	if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
348 	    size_t start_buf = buf->content - buf->contentIO;
349 	    if (start_buf >= buf->size) {
350 		memmove(buf->contentIO, &buf->content[0], buf->use);
351 		buf->content = buf->contentIO;
352 		buf->content[buf->use] = 0;
353 		buf->size += start_buf;
354 	    }
355 	}
356     } else {
357 	memmove(buf->content, &buf->content[len], buf->use);
358 	buf->content[buf->use] = 0;
359     }
360     UPDATE_COMPAT(buf)
361     return(len);
362 }
363 
364 /**
365  * xmlBufGrowInternal:
366  * @buf:  the buffer
367  * @len:  the minimum free size to allocate
368  *
369  * Grow the available space of an XML buffer, @len is the target value
370  * Error checking should be done on buf->error since using the return
371  * value doesn't work that well
372  *
373  * Returns 0 in case of error or the length made available otherwise
374  */
375 static size_t
xmlBufGrowInternal(xmlBufPtr buf,size_t len)376 xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
377     size_t size;
378     xmlChar *newbuf;
379 
380     if ((buf == NULL) || (buf->error != 0)) return(0);
381     CHECK_COMPAT(buf)
382 
383     if (len < buf->size - buf->use)
384         return(buf->size - buf->use - 1);
385     if (len >= SIZE_MAX - buf->use) {
386         xmlBufMemoryError(buf);
387         return(0);
388     }
389 
390     if (buf->size > (size_t) len) {
391         size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
392     } else {
393         size = buf->use + len;
394         size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
395     }
396 
397     if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
398         /*
399 	 * Used to provide parsing limits
400 	 */
401         if ((buf->use + len + 1 >= XML_MAX_TEXT_LENGTH) ||
402 	    (buf->size >= XML_MAX_TEXT_LENGTH)) {
403 	    xmlBufMemoryError(buf);
404 	    return(0);
405 	}
406 	if (size >= XML_MAX_TEXT_LENGTH)
407 	    size = XML_MAX_TEXT_LENGTH;
408     }
409     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
410         size_t start_buf = buf->content - buf->contentIO;
411 
412 	newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
413 	if (newbuf == NULL) {
414 	    xmlBufMemoryError(buf);
415 	    return(0);
416 	}
417 	buf->contentIO = newbuf;
418 	buf->content = newbuf + start_buf;
419     } else {
420 	newbuf = (xmlChar *) xmlRealloc(buf->content, size);
421 	if (newbuf == NULL) {
422 	    xmlBufMemoryError(buf);
423 	    return(0);
424 	}
425 	buf->content = newbuf;
426     }
427     buf->size = size;
428     UPDATE_COMPAT(buf)
429     return(buf->size - buf->use - 1);
430 }
431 
432 /**
433  * xmlBufGrow:
434  * @buf:  the buffer
435  * @len:  the minimum free size to allocate
436  *
437  * Grow the available space of an XML buffer, @len is the target value
438  * This is been kept compatible with xmlBufferGrow() as much as possible
439  *
440  * Returns -1 in case of error or the length made available otherwise
441  */
442 int
xmlBufGrow(xmlBufPtr buf,int len)443 xmlBufGrow(xmlBufPtr buf, int len) {
444     size_t ret;
445 
446     if ((buf == NULL) || (len < 0)) return(-1);
447     if (len == 0)
448         return(0);
449     ret = xmlBufGrowInternal(buf, len);
450     if (buf->error != 0)
451         return(-1);
452     return(ret > INT_MAX ? INT_MAX : ret);
453 }
454 
455 /**
456  * xmlBufDump:
457  * @file:  the file output
458  * @buf:  the buffer to dump
459  *
460  * Dumps an XML buffer to  a FILE *.
461  * Returns the number of #xmlChar written
462  */
463 size_t
xmlBufDump(FILE * file,xmlBufPtr buf)464 xmlBufDump(FILE *file, xmlBufPtr buf) {
465     size_t ret;
466 
467     if ((buf == NULL) || (buf->error != 0)) {
468 	return(0);
469     }
470     if (buf->content == NULL) {
471 	return(0);
472     }
473     CHECK_COMPAT(buf)
474     if (file == NULL)
475 	file = stdout;
476     ret = fwrite(buf->content, 1, buf->use, file);
477     return(ret);
478 }
479 
480 /**
481  * xmlBufContent:
482  * @buf:  the buffer
483  *
484  * Function to extract the content of a buffer
485  *
486  * Returns the internal content
487  */
488 
489 xmlChar *
xmlBufContent(const xmlBuf * buf)490 xmlBufContent(const xmlBuf *buf)
491 {
492     if ((!buf) || (buf->error))
493         return NULL;
494 
495     return(buf->content);
496 }
497 
498 /**
499  * xmlBufEnd:
500  * @buf:  the buffer
501  *
502  * Function to extract the end of the content of a buffer
503  *
504  * Returns the end of the internal content or NULL in case of error
505  */
506 
507 xmlChar *
xmlBufEnd(xmlBufPtr buf)508 xmlBufEnd(xmlBufPtr buf)
509 {
510     if ((!buf) || (buf->error))
511         return NULL;
512     CHECK_COMPAT(buf)
513 
514     return(&buf->content[buf->use]);
515 }
516 
517 /**
518  * xmlBufAddLen:
519  * @buf:  the buffer
520  * @len:  the size which were added at the end
521  *
522  * Sometime data may be added at the end of the buffer without
523  * using the xmlBuf APIs that is used to expand the used space
524  * and set the zero terminating at the end of the buffer
525  *
526  * Returns -1 in case of error and 0 otherwise
527  */
528 int
xmlBufAddLen(xmlBufPtr buf,size_t len)529 xmlBufAddLen(xmlBufPtr buf, size_t len) {
530     if ((buf == NULL) || (buf->error))
531         return(-1);
532     CHECK_COMPAT(buf)
533     if (len >= (buf->size - buf->use))
534         return(-1);
535     buf->use += len;
536     buf->content[buf->use] = 0;
537     UPDATE_COMPAT(buf)
538     return(0);
539 }
540 
541 /**
542  * xmlBufLength:
543  * @buf:  the buffer
544  *
545  * Function to get the length of a buffer
546  *
547  * Returns the length of data in the internal content
548  */
549 
550 size_t
xmlBufLength(const xmlBufPtr buf)551 xmlBufLength(const xmlBufPtr buf)
552 {
553     if ((!buf) || (buf->error))
554         return 0;
555     CHECK_COMPAT(buf)
556 
557     return(buf->use);
558 }
559 
560 /**
561  * xmlBufUse:
562  * @buf:  the buffer
563  *
564  * Function to get the length of a buffer
565  *
566  * Returns the length of data in the internal content
567  */
568 
569 size_t
xmlBufUse(const xmlBufPtr buf)570 xmlBufUse(const xmlBufPtr buf)
571 {
572     if ((!buf) || (buf->error))
573         return 0;
574     CHECK_COMPAT(buf)
575 
576     return(buf->use);
577 }
578 
579 /**
580  * xmlBufAvail:
581  * @buf:  the buffer
582  *
583  * Function to find how much free space is allocated but not
584  * used in the buffer. It reserves one byte for the NUL
585  * terminator character that is usually needed, so there is
586  * no need to subtract 1 from the result anymore.
587  *
588  * Returns the amount, or 0 if none or if an error occurred.
589  */
590 
591 size_t
xmlBufAvail(const xmlBufPtr buf)592 xmlBufAvail(const xmlBufPtr buf)
593 {
594     if ((!buf) || (buf->error))
595         return 0;
596     CHECK_COMPAT(buf)
597 
598     return((buf->size > buf->use) ? (buf->size - buf->use - 1) : 0);
599 }
600 
601 /**
602  * xmlBufIsEmpty:
603  * @buf:  the buffer
604  *
605  * Tell if a buffer is empty
606  *
607  * Returns 0 if no, 1 if yes and -1 in case of error
608  */
609 int
xmlBufIsEmpty(const xmlBufPtr buf)610 xmlBufIsEmpty(const xmlBufPtr buf)
611 {
612     if ((!buf) || (buf->error))
613         return(-1);
614     CHECK_COMPAT(buf)
615 
616     return(buf->use == 0);
617 }
618 
619 /**
620  * xmlBufResize:
621  * @buf:  the buffer to resize
622  * @size:  the desired size
623  *
624  * Resize a buffer to accommodate minimum size of @size.
625  *
626  * Returns  0 in case of problems, 1 otherwise
627  */
628 int
xmlBufResize(xmlBufPtr buf,size_t size)629 xmlBufResize(xmlBufPtr buf, size_t size)
630 {
631     size_t newSize;
632     xmlChar* rebuf = NULL;
633     size_t start_buf;
634 
635     if ((buf == NULL) || (buf->error))
636         return(0);
637     CHECK_COMPAT(buf)
638 
639     if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
640         /*
641 	 * Used to provide parsing limits
642 	 */
643         if (size >= XML_MAX_TEXT_LENGTH) {
644 	    xmlBufMemoryError(buf);
645 	    return(0);
646 	}
647     }
648 
649     /* Don't resize if we don't have to */
650     if (size < buf->size)
651         return 1;
652 
653     /* figure out new size */
654     switch (buf->alloc){
655 	case XML_BUFFER_ALLOC_IO:
656 	case XML_BUFFER_ALLOC_DOUBLEIT:
657 	    /*take care of empty case*/
658             if (buf->size == 0) {
659                 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
660             } else {
661                 newSize = buf->size;
662             }
663 	    while (size > newSize) {
664 	        if (newSize > SIZE_MAX / 2) {
665 	            xmlBufMemoryError(buf);
666 	            return 0;
667 	        }
668 	        newSize *= 2;
669 	    }
670 	    break;
671 	case XML_BUFFER_ALLOC_EXACT:
672             newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
673 	    break;
674         case XML_BUFFER_ALLOC_HYBRID:
675             if (buf->use < BASE_BUFFER_SIZE)
676                 newSize = size;
677             else {
678                 newSize = buf->size;
679                 while (size > newSize) {
680                     if (newSize > SIZE_MAX / 2) {
681                         xmlBufMemoryError(buf);
682                         return 0;
683                     }
684                     newSize *= 2;
685                 }
686             }
687             break;
688 
689 	default:
690             newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
691 	    break;
692     }
693 
694     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
695         start_buf = buf->content - buf->contentIO;
696 
697         if (start_buf > newSize) {
698 	    /* move data back to start */
699 	    memmove(buf->contentIO, buf->content, buf->use);
700 	    buf->content = buf->contentIO;
701 	    buf->content[buf->use] = 0;
702 	    buf->size += start_buf;
703 	} else {
704 	    rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
705 	    if (rebuf == NULL) {
706 		xmlBufMemoryError(buf);
707 		return 0;
708 	    }
709 	    buf->contentIO = rebuf;
710 	    buf->content = rebuf + start_buf;
711 	}
712     } else {
713 	if (buf->content == NULL) {
714 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
715 	    buf->use = 0;
716             if (rebuf != NULL)
717 	        rebuf[buf->use] = 0;
718 	} else if (buf->size - buf->use < 100) {
719 	    rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
720         } else {
721 	    /*
722 	     * if we are reallocating a buffer far from being full, it's
723 	     * better to make a new allocation and copy only the used range
724 	     * and free the old one.
725 	     */
726 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
727 	    if (rebuf != NULL) {
728 		memcpy(rebuf, buf->content, buf->use);
729 		xmlFree(buf->content);
730 		rebuf[buf->use] = 0;
731 	    }
732 	}
733 	if (rebuf == NULL) {
734 	    xmlBufMemoryError(buf);
735 	    return 0;
736 	}
737 	buf->content = rebuf;
738     }
739     buf->size = newSize;
740     UPDATE_COMPAT(buf)
741 
742     return 1;
743 }
744 
745 /**
746  * xmlBufAdd:
747  * @buf:  the buffer to dump
748  * @str:  the #xmlChar string
749  * @len:  the number of #xmlChar to add
750  *
751  * Add a string range to an XML buffer. if len == -1, the length of
752  * str is recomputed.
753  *
754  * Returns 0 if successful, -1 in case of error.
755  */
756 int
xmlBufAdd(xmlBufPtr buf,const xmlChar * str,int len)757 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
758     size_t needSize;
759 
760     if ((str == NULL) || (buf == NULL) || (buf->error))
761 	return -1;
762     CHECK_COMPAT(buf)
763 
764     if (len < -1) {
765 	return -1;
766     }
767     if (len == 0) return 0;
768 
769     if (len < 0)
770         len = xmlStrlen(str);
771 
772     if (len < 0) return -1;
773     if (len == 0) return 0;
774 
775     /* Note that both buf->size and buf->use can be zero here. */
776     if ((size_t) len >= buf->size - buf->use) {
777         if ((size_t) len >= SIZE_MAX - buf->use) {
778             xmlBufMemoryError(buf);
779             return(-1);
780         }
781         needSize = buf->use + len + 1;
782 	if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
783 	    /*
784 	     * Used to provide parsing limits
785 	     */
786 	    if (needSize >= XML_MAX_TEXT_LENGTH) {
787 		xmlBufMemoryError(buf);
788 		return(-1);
789 	    }
790 	}
791         if (!xmlBufResize(buf, needSize))
792             return(-1);
793     }
794 
795     memmove(&buf->content[buf->use], str, len);
796     buf->use += len;
797     buf->content[buf->use] = 0;
798     UPDATE_COMPAT(buf)
799     return 0;
800 }
801 
802 /**
803  * xmlBufCat:
804  * @buf:  the buffer to add to
805  * @str:  the #xmlChar string
806  *
807  * Append a zero terminated string to an XML buffer.
808  *
809  * Returns 0 successful, a positive error code number otherwise
810  *         and -1 in case of internal or API error.
811  */
812 int
xmlBufCat(xmlBufPtr buf,const xmlChar * str)813 xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
814     if ((buf == NULL) || (buf->error))
815         return(-1);
816     CHECK_COMPAT(buf)
817     if (str == NULL) return -1;
818     return xmlBufAdd(buf, str, -1);
819 }
820 
821 /**
822  * xmlBufFromBuffer:
823  * @buffer: incoming old buffer to convert to a new one
824  *
825  * Helper routine to switch from the old buffer structures in use
826  * in various APIs. It creates a wrapper xmlBufPtr which will be
827  * used for internal processing until the xmlBufBackToBuffer() is
828  * issued.
829  *
830  * Returns a new xmlBufPtr unless the call failed and NULL is returned
831  */
832 xmlBufPtr
xmlBufFromBuffer(xmlBufferPtr buffer)833 xmlBufFromBuffer(xmlBufferPtr buffer) {
834     xmlBufPtr ret;
835 
836     if (buffer == NULL)
837         return(NULL);
838 
839     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
840     if (ret == NULL) {
841         return(NULL);
842     }
843     ret->use = buffer->use;
844     ret->size = buffer->size;
845     UPDATE_COMPAT(ret);
846     ret->error = 0;
847     ret->buffer = buffer;
848     ret->alloc = buffer->alloc;
849     ret->content = buffer->content;
850     ret->contentIO = buffer->contentIO;
851 
852     return(ret);
853 }
854 
855 /**
856  * xmlBufBackToBuffer:
857  * @buf: new buffer wrapping the old one
858  *
859  * Function to be called once internal processing had been done to
860  * update back the buffer provided by the user. This can lead to
861  * a failure in case the size accumulated in the xmlBuf is larger
862  * than what an xmlBuffer can support on 64 bits (INT_MAX)
863  * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
864  *
865  * Returns the old xmlBufferPtr unless the call failed and NULL is returned
866  */
867 xmlBufferPtr
xmlBufBackToBuffer(xmlBufPtr buf)868 xmlBufBackToBuffer(xmlBufPtr buf) {
869     xmlBufferPtr ret;
870 
871     if (buf == NULL)
872         return(NULL);
873     CHECK_COMPAT(buf)
874     ret = buf->buffer;
875 
876     if ((buf->error) || (ret == NULL)) {
877         xmlBufFree(buf);
878         if (ret != NULL) {
879             ret->content = NULL;
880             ret->contentIO = NULL;
881             ret->use = 0;
882             ret->size = 0;
883         }
884         return(NULL);
885     }
886 
887     /*
888      * What to do in case of error in the buffer ???
889      */
890     if (buf->use > INT_MAX) {
891         /*
892          * Worse case, we really allocated and used more than the
893          * maximum allowed memory for an xmlBuffer on this architecture.
894          * Keep the buffer but provide a truncated size value.
895          */
896         xmlBufOverflowError(buf);
897         ret->use = INT_MAX;
898         ret->size = INT_MAX;
899     } else if (buf->size > INT_MAX) {
900         /*
901          * milder case, we allocated more than the maximum allowed memory
902          * for an xmlBuffer on this architecture, but used less than the
903          * limit.
904          * Keep the buffer but provide a truncated size value.
905          */
906         xmlBufOverflowError(buf);
907         ret->use = buf->use;
908         ret->size = INT_MAX;
909     } else {
910         ret->use = buf->use;
911         ret->size = buf->size;
912     }
913     ret->alloc = buf->alloc;
914     ret->content = buf->content;
915     ret->contentIO = buf->contentIO;
916     xmlFree(buf);
917     return(ret);
918 }
919 
920 /**
921  * xmlBufResetInput:
922  * @buf: an xmlBufPtr
923  * @input: an xmlParserInputPtr
924  *
925  * Update the input to use the current set of pointers from the buffer.
926  *
927  * Returns -1 in case of error, 0 otherwise
928  */
929 int
xmlBufResetInput(xmlBufPtr buf,xmlParserInputPtr input)930 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
931     return(xmlBufUpdateInput(buf, input, 0));
932 }
933 
934 /**
935  * xmlBufUpdateInput:
936  * @buf: an xmlBufPtr
937  * @input: an xmlParserInputPtr
938  * @pos: the cur value relative to the beginning of the buffer
939  *
940  * Update the input to use the base and cur relative to the buffer
941  * after a possible reallocation of its content
942  *
943  * Returns -1 in case of error, 0 otherwise
944  */
945 int
xmlBufUpdateInput(xmlBufPtr buf,xmlParserInputPtr input,size_t pos)946 xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
947     if ((buf == NULL) || (input == NULL))
948         return(-1);
949     CHECK_COMPAT(buf)
950     input->base = buf->content;
951     input->cur = input->base + pos;
952     input->end = &buf->content[buf->use];
953     return(0);
954 }
955 
956