• 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,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 information
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->use = 0;
131     ret->error = 0;
132     ret->buffer = NULL;
133     ret->size = xmlDefaultBufferSize;
134     UPDATE_COMPAT(ret);
135     ret->alloc = xmlBufferAllocScheme;
136     ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
137     if (ret->content == NULL) {
138 	xmlBufMemoryError(ret, "creating buffer");
139 	xmlFree(ret);
140         return(NULL);
141     }
142     ret->content[0] = 0;
143     ret->contentIO = NULL;
144     return(ret);
145 }
146 
147 /**
148  * xmlBufCreateSize:
149  * @size: initial size of buffer
150  *
151  * routine to create an XML buffer.
152  * returns the new structure.
153  */
154 xmlBufPtr
xmlBufCreateSize(size_t size)155 xmlBufCreateSize(size_t size) {
156     xmlBufPtr ret;
157 
158     if (size == SIZE_MAX)
159         return(NULL);
160     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
161     if (ret == NULL) {
162 	xmlBufMemoryError(NULL, "creating buffer");
163         return(NULL);
164     }
165     ret->use = 0;
166     ret->error = 0;
167     ret->buffer = NULL;
168     ret->alloc = xmlBufferAllocScheme;
169     ret->size = (size ? size + 1 : 0);         /* +1 for ending null */
170     UPDATE_COMPAT(ret);
171     if (ret->size){
172         ret->content = (xmlChar *) xmlMallocAtomic(ret->size);
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->buffer != NULL)
202         return(NULL);
203     if (buf->error)
204         return(NULL);
205 
206     ret = buf->content;
207     buf->content = 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, "growing buffer past SIZE_MAX");
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, "buffer error: text too long\n");
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, "growing buffer");
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, "growing buffer");
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, "buffer error: text too long\n");
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, "growing buffer");
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, "growing buffer");
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, "growing buffer");
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, "growing buffer");
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 successful, a positive error code number otherwise
755  *         and -1 in case of internal or API error.
756  */
757 int
xmlBufAdd(xmlBufPtr buf,const xmlChar * str,int len)758 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
759     size_t needSize;
760 
761     if ((str == NULL) || (buf == NULL) || (buf->error))
762 	return -1;
763     CHECK_COMPAT(buf)
764 
765     if (len < -1) {
766 	return -1;
767     }
768     if (len == 0) return 0;
769 
770     if (len < 0)
771         len = xmlStrlen(str);
772 
773     if (len < 0) return -1;
774     if (len == 0) return 0;
775 
776     /* Note that both buf->size and buf->use can be zero here. */
777     if ((size_t) len >= buf->size - buf->use) {
778         if ((size_t) len >= SIZE_MAX - buf->use) {
779             xmlBufMemoryError(buf, "growing buffer past SIZE_MAX");
780             return(-1);
781         }
782         needSize = buf->use + len + 1;
783 	if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
784 	    /*
785 	     * Used to provide parsing limits
786 	     */
787 	    if (needSize >= XML_MAX_TEXT_LENGTH) {
788 		xmlBufMemoryError(buf, "buffer error: text too long\n");
789 		return(-1);
790 	    }
791 	}
792         if (!xmlBufResize(buf, needSize)){
793 	    xmlBufMemoryError(buf, "growing buffer");
794             return XML_ERR_NO_MEMORY;
795         }
796     }
797 
798     memmove(&buf->content[buf->use], str, len);
799     buf->use += len;
800     buf->content[buf->use] = 0;
801     UPDATE_COMPAT(buf)
802     return 0;
803 }
804 
805 /**
806  * xmlBufCat:
807  * @buf:  the buffer to add to
808  * @str:  the #xmlChar string
809  *
810  * Append a zero terminated string to an XML buffer.
811  *
812  * Returns 0 successful, a positive error code number otherwise
813  *         and -1 in case of internal or API error.
814  */
815 int
xmlBufCat(xmlBufPtr buf,const xmlChar * str)816 xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
817     if ((buf == NULL) || (buf->error))
818         return(-1);
819     CHECK_COMPAT(buf)
820     if (str == NULL) return -1;
821     return xmlBufAdd(buf, str, -1);
822 }
823 
824 /**
825  * xmlBufCCat:
826  * @buf:  the buffer to dump
827  * @str:  the C char string
828  *
829  * Append a zero terminated C string to an XML buffer.
830  *
831  * Returns 0 successful, a positive error code number otherwise
832  *         and -1 in case of internal or API error.
833  */
834 int
xmlBufCCat(xmlBufPtr buf,const char * str)835 xmlBufCCat(xmlBufPtr buf, const char *str) {
836     return xmlBufCat(buf, (const xmlChar *) str);
837 }
838 
839 /**
840  * xmlBufWriteQuotedString:
841  * @buf:  the XML buffer output
842  * @string:  the string to add
843  *
844  * routine which manage and grows an output buffer. This one writes
845  * a quoted or double quoted #xmlChar string, checking first if it holds
846  * quote or double-quotes internally
847  *
848  * Returns 0 if successful, a positive error code number otherwise
849  *         and -1 in case of internal or API error.
850  */
851 int
xmlBufWriteQuotedString(xmlBufPtr buf,const xmlChar * string)852 xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
853     const xmlChar *cur, *base;
854     if ((buf == NULL) || (buf->error))
855         return(-1);
856     CHECK_COMPAT(buf)
857     if (xmlStrchr(string, '\"')) {
858         if (xmlStrchr(string, '\'')) {
859 	    xmlBufCCat(buf, "\"");
860             base = cur = string;
861             while(*cur != 0){
862                 if(*cur == '"'){
863                     if (base != cur)
864                         xmlBufAdd(buf, base, cur - base);
865                     xmlBufAdd(buf, BAD_CAST "&quot;", 6);
866                     cur++;
867                     base = cur;
868                 }
869                 else {
870                     cur++;
871                 }
872             }
873             if (base != cur)
874                 xmlBufAdd(buf, base, cur - base);
875 	    xmlBufCCat(buf, "\"");
876 	}
877         else{
878 	    xmlBufCCat(buf, "\'");
879             xmlBufCat(buf, string);
880 	    xmlBufCCat(buf, "\'");
881         }
882     } else {
883         xmlBufCCat(buf, "\"");
884         xmlBufCat(buf, string);
885         xmlBufCCat(buf, "\"");
886     }
887     return(0);
888 }
889 
890 /**
891  * xmlBufFromBuffer:
892  * @buffer: incoming old buffer to convert to a new one
893  *
894  * Helper routine to switch from the old buffer structures in use
895  * in various APIs. It creates a wrapper xmlBufPtr which will be
896  * used for internal processing until the xmlBufBackToBuffer() is
897  * issued.
898  *
899  * Returns a new xmlBufPtr unless the call failed and NULL is returned
900  */
901 xmlBufPtr
xmlBufFromBuffer(xmlBufferPtr buffer)902 xmlBufFromBuffer(xmlBufferPtr buffer) {
903     xmlBufPtr ret;
904 
905     if (buffer == NULL)
906         return(NULL);
907 
908     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
909     if (ret == NULL) {
910 	xmlBufMemoryError(NULL, "creating buffer");
911         return(NULL);
912     }
913     ret->use = buffer->use;
914     ret->size = buffer->size;
915     UPDATE_COMPAT(ret);
916     ret->error = 0;
917     ret->buffer = buffer;
918     ret->alloc = buffer->alloc;
919     ret->content = buffer->content;
920     ret->contentIO = buffer->contentIO;
921 
922     return(ret);
923 }
924 
925 /**
926  * xmlBufBackToBuffer:
927  * @buf: new buffer wrapping the old one
928  *
929  * Function to be called once internal processing had been done to
930  * update back the buffer provided by the user. This can lead to
931  * a failure in case the size accumulated in the xmlBuf is larger
932  * than what an xmlBuffer can support on 64 bits (INT_MAX)
933  * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
934  *
935  * Returns the old xmlBufferPtr unless the call failed and NULL is returned
936  */
937 xmlBufferPtr
xmlBufBackToBuffer(xmlBufPtr buf)938 xmlBufBackToBuffer(xmlBufPtr buf) {
939     xmlBufferPtr ret;
940 
941     if (buf == NULL)
942         return(NULL);
943     CHECK_COMPAT(buf)
944     if ((buf->error) || (buf->buffer == NULL)) {
945         xmlBufFree(buf);
946         return(NULL);
947     }
948 
949     ret = buf->buffer;
950     /*
951      * What to do in case of error in the buffer ???
952      */
953     if (buf->use > INT_MAX) {
954         /*
955          * Worse case, we really allocated and used more than the
956          * maximum allowed memory for an xmlBuffer on this architecture.
957          * Keep the buffer but provide a truncated size value.
958          */
959         xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
960         ret->use = INT_MAX;
961         ret->size = INT_MAX;
962     } else if (buf->size > INT_MAX) {
963         /*
964          * milder case, we allocated more than the maximum allowed memory
965          * for an xmlBuffer on this architecture, but used less than the
966          * limit.
967          * Keep the buffer but provide a truncated size value.
968          */
969         xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
970         ret->use = buf->use;
971         ret->size = INT_MAX;
972     } else {
973         ret->use = buf->use;
974         ret->size = buf->size;
975     }
976     ret->alloc = buf->alloc;
977     ret->content = buf->content;
978     ret->contentIO = buf->contentIO;
979     xmlFree(buf);
980     return(ret);
981 }
982 
983 /**
984  * xmlBufMergeBuffer:
985  * @buf: an xmlBufPtr
986  * @buffer: the buffer to consume into @buf
987  *
988  * The content of @buffer is appended to @buf and @buffer is freed
989  *
990  * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
991  */
992 int
xmlBufMergeBuffer(xmlBufPtr buf,xmlBufferPtr buffer)993 xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
994     int ret = 0;
995 
996     if ((buf == NULL) || (buf->error)) {
997 	xmlBufferFree(buffer);
998         return(-1);
999     }
1000     CHECK_COMPAT(buf)
1001     if ((buffer != NULL) && (buffer->content != NULL) &&
1002              (buffer->use > 0)) {
1003         ret = xmlBufAdd(buf, buffer->content, buffer->use);
1004     }
1005     xmlBufferFree(buffer);
1006     return(ret);
1007 }
1008 
1009 /**
1010  * xmlBufResetInput:
1011  * @buf: an xmlBufPtr
1012  * @input: an xmlParserInputPtr
1013  *
1014  * Update the input to use the current set of pointers from the buffer.
1015  *
1016  * Returns -1 in case of error, 0 otherwise
1017  */
1018 int
xmlBufResetInput(xmlBufPtr buf,xmlParserInputPtr input)1019 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
1020     if (input == NULL)
1021         return(-1);
1022     if ((buf == NULL) || (buf->error)) {
1023         input->base = input->cur = input->end = BAD_CAST "";
1024         return(-1);
1025     }
1026     CHECK_COMPAT(buf)
1027     input->base = input->cur = buf->content;
1028     input->end = &buf->content[buf->use];
1029     return(0);
1030 }
1031 
1032 /**
1033  * xmlBufUpdateInput:
1034  * @buf: an xmlBufPtr
1035  * @input: an xmlParserInputPtr
1036  * @pos: the cur value relative to the beginning of the buffer
1037  *
1038  * Update the input to use the base and cur relative to the buffer
1039  * after a possible reallocation of its content
1040  *
1041  * Returns -1 in case of error, 0 otherwise
1042  */
1043 int
xmlBufUpdateInput(xmlBufPtr buf,xmlParserInputPtr input,size_t pos)1044 xmlBufUpdateInput(xmlBufPtr buf, xmlParserInputPtr input, size_t pos) {
1045     if (input == NULL)
1046         return(-1);
1047     /*
1048      * TODO: It might be safer to keep using the buffer content if there
1049      * was an error.
1050      */
1051     if ((buf == NULL) || (buf->error)) {
1052         input->base = input->cur = input->end = BAD_CAST "";
1053         return(-1);
1054     }
1055     CHECK_COMPAT(buf)
1056     input->base = buf->content;
1057     input->cur = input->base + pos;
1058     input->end = &buf->content[buf->use];
1059     return(0);
1060 }
1061 
1062