xref: /reactos/sdk/lib/3rdparty/libxml2/buf.c (revision 911153da)
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/globals.h>
25 #include <libxml/tree.h>
26 #include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
27 #include "buf.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 * sizeof(xmlChar));
137     if (ret->content == NULL) {
138 	xmlBufMemoryError(ret, "creating buffer");
139 	xmlFree(ret);
140         return(NULL);
141     }
142     ret->content[0] = 0;
143     ret->contentIO = NULL;
144     return(ret);
145 }
146 
147 /**
148  * xmlBufCreateSize:
149  * @size: initial size of buffer
150  *
151  * routine to create an XML buffer.
152  * returns the new structure.
153  */
154 xmlBufPtr
xmlBufCreateSize(size_t size)155 xmlBufCreateSize(size_t size) {
156     xmlBufPtr ret;
157 
158     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 * sizeof(xmlChar));
173         if (ret->content == NULL) {
174 	    xmlBufMemoryError(ret, "creating buffer");
175             xmlFree(ret);
176             return(NULL);
177         }
178         ret->content[0] = 0;
179     } else
180 	ret->content = NULL;
181     ret->contentIO = NULL;
182     return(ret);
183 }
184 
185 /**
186  * xmlBufDetach:
187  * @buf:  the buffer
188  *
189  * Remove the string contained in a buffer and give it back to the
190  * caller. The buffer is reset to an empty content.
191  * This doesn't work with immutable buffers as they can't be reset.
192  *
193  * Returns the previous string contained by the buffer.
194  */
195 xmlChar *
xmlBufDetach(xmlBufPtr buf)196 xmlBufDetach(xmlBufPtr buf) {
197     xmlChar *ret;
198 
199     if (buf == NULL)
200         return(NULL);
201     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
202         return(NULL);
203     if (buf->buffer != NULL)
204         return(NULL);
205     if (buf->error)
206         return(NULL);
207 
208     ret = buf->content;
209     buf->content = NULL;
210     buf->size = 0;
211     buf->use = 0;
212     UPDATE_COMPAT(buf);
213 
214     return ret;
215 }
216 
217 
218 /**
219  * xmlBufCreateStatic:
220  * @mem: the memory area
221  * @size:  the size in byte
222  *
223  * routine to create an XML buffer from an immutable memory area.
224  * The area won't be modified nor copied, and is expected to be
225  * present until the end of the buffer lifetime.
226  *
227  * returns the new structure.
228  */
229 xmlBufPtr
xmlBufCreateStatic(void * mem,size_t size)230 xmlBufCreateStatic(void *mem, size_t size) {
231     xmlBufPtr ret;
232 
233     if (mem == NULL)
234         return(NULL);
235 
236     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
237     if (ret == NULL) {
238 	xmlBufMemoryError(NULL, "creating buffer");
239         return(NULL);
240     }
241     ret->use = size;
242     ret->size = size;
243     UPDATE_COMPAT(ret);
244     ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
245     ret->content = (xmlChar *) mem;
246     ret->error = 0;
247     ret->buffer = NULL;
248     return(ret);
249 }
250 
251 /**
252  * xmlBufGetAllocationScheme:
253  * @buf:  the buffer
254  *
255  * Get the buffer allocation scheme
256  *
257  * Returns the scheme or -1 in case of error
258  */
259 int
xmlBufGetAllocationScheme(xmlBufPtr buf)260 xmlBufGetAllocationScheme(xmlBufPtr buf) {
261     if (buf == NULL) {
262 #ifdef DEBUG_BUFFER
263         xmlGenericError(xmlGenericErrorContext,
264 		"xmlBufGetAllocationScheme: buf == NULL\n");
265 #endif
266         return(-1);
267     }
268     return(buf->alloc);
269 }
270 
271 /**
272  * xmlBufSetAllocationScheme:
273  * @buf:  the buffer to tune
274  * @scheme:  allocation scheme to use
275  *
276  * Sets the allocation scheme for this buffer
277  *
278  * returns 0 in case of success and -1 in case of failure
279  */
280 int
xmlBufSetAllocationScheme(xmlBufPtr buf,xmlBufferAllocationScheme scheme)281 xmlBufSetAllocationScheme(xmlBufPtr buf,
282                           xmlBufferAllocationScheme scheme) {
283     if ((buf == NULL) || (buf->error != 0)) {
284 #ifdef DEBUG_BUFFER
285         xmlGenericError(xmlGenericErrorContext,
286 		"xmlBufSetAllocationScheme: buf == NULL or in error\n");
287 #endif
288         return(-1);
289     }
290     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
291         (buf->alloc == XML_BUFFER_ALLOC_IO))
292         return(-1);
293     if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
294         (scheme == XML_BUFFER_ALLOC_EXACT) ||
295         (scheme == XML_BUFFER_ALLOC_HYBRID) ||
296         (scheme == XML_BUFFER_ALLOC_IMMUTABLE) ||
297 	(scheme == XML_BUFFER_ALLOC_BOUNDED)) {
298 	buf->alloc = scheme;
299         if (buf->buffer)
300             buf->buffer->alloc = scheme;
301         return(0);
302     }
303     /*
304      * Switching a buffer ALLOC_IO has the side effect of initializing
305      * the contentIO field with the current content
306      */
307     if (scheme == XML_BUFFER_ALLOC_IO) {
308         buf->alloc = XML_BUFFER_ALLOC_IO;
309         buf->contentIO = buf->content;
310     }
311     return(-1);
312 }
313 
314 /**
315  * xmlBufFree:
316  * @buf:  the buffer to free
317  *
318  * Frees an XML buffer. It frees both the content and the structure which
319  * encapsulate it.
320  */
321 void
xmlBufFree(xmlBufPtr buf)322 xmlBufFree(xmlBufPtr buf) {
323     if (buf == NULL) {
324 #ifdef DEBUG_BUFFER
325         xmlGenericError(xmlGenericErrorContext,
326 		"xmlBufFree: buf == NULL\n");
327 #endif
328 	return;
329     }
330 
331     if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
332         (buf->contentIO != NULL)) {
333         xmlFree(buf->contentIO);
334     } else if ((buf->content != NULL) &&
335         (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
336         xmlFree(buf->content);
337     }
338     xmlFree(buf);
339 }
340 
341 /**
342  * xmlBufEmpty:
343  * @buf:  the buffer
344  *
345  * empty a buffer.
346  */
347 void
xmlBufEmpty(xmlBufPtr buf)348 xmlBufEmpty(xmlBufPtr buf) {
349     if ((buf == NULL) || (buf->error != 0)) return;
350     if (buf->content == NULL) return;
351     CHECK_COMPAT(buf)
352     buf->use = 0;
353     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
354         buf->content = BAD_CAST "";
355     } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
356                (buf->contentIO != NULL)) {
357         size_t start_buf = buf->content - buf->contentIO;
358 
359 	buf->size += start_buf;
360         buf->content = buf->contentIO;
361         buf->content[0] = 0;
362     } else {
363         buf->content[0] = 0;
364     }
365     UPDATE_COMPAT(buf)
366 }
367 
368 /**
369  * xmlBufShrink:
370  * @buf:  the buffer to dump
371  * @len:  the number of xmlChar to remove
372  *
373  * Remove the beginning of an XML buffer.
374  * NOTE that this routine behaviour differs from xmlBufferShrink()
375  * as it will return 0 on error instead of -1 due to size_t being
376  * used as the return type.
377  *
378  * Returns the number of byte removed or 0 in case of failure
379  */
380 size_t
xmlBufShrink(xmlBufPtr buf,size_t len)381 xmlBufShrink(xmlBufPtr buf, size_t len) {
382     if ((buf == NULL) || (buf->error != 0)) return(0);
383     CHECK_COMPAT(buf)
384     if (len == 0) return(0);
385     if (len > buf->use) return(0);
386 
387     buf->use -= len;
388     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
389         ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
390 	/*
391 	 * we just move the content pointer, but also make sure
392 	 * the perceived buffer size has shrunk accordingly
393 	 */
394         buf->content += len;
395 	buf->size -= len;
396 
397         /*
398 	 * sometimes though it maybe be better to really shrink
399 	 * on IO buffers
400 	 */
401 	if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
402 	    size_t start_buf = buf->content - buf->contentIO;
403 	    if (start_buf >= buf->size) {
404 		memmove(buf->contentIO, &buf->content[0], buf->use);
405 		buf->content = buf->contentIO;
406 		buf->content[buf->use] = 0;
407 		buf->size += start_buf;
408 	    }
409 	}
410     } else {
411 	memmove(buf->content, &buf->content[len], buf->use);
412 	buf->content[buf->use] = 0;
413     }
414     UPDATE_COMPAT(buf)
415     return(len);
416 }
417 
418 /**
419  * xmlBufGrowInternal:
420  * @buf:  the buffer
421  * @len:  the minimum free size to allocate
422  *
423  * Grow the available space of an XML buffer, @len is the target value
424  * Error checking should be done on buf->error since using the return
425  * value doesn't work that well
426  *
427  * Returns 0 in case of error or the length made available otherwise
428  */
429 static size_t
xmlBufGrowInternal(xmlBufPtr buf,size_t len)430 xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
431     size_t size;
432     xmlChar *newbuf;
433 
434     if ((buf == NULL) || (buf->error != 0)) return(0);
435     CHECK_COMPAT(buf)
436 
437     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
438     if (len < buf->size - buf->use)
439         return(buf->size - buf->use - 1);
440     if (len >= SIZE_MAX - buf->use) {
441         xmlBufMemoryError(buf, "growing buffer past SIZE_MAX");
442         return(0);
443     }
444 
445     if (buf->size > (size_t) len) {
446         size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
447     } else {
448         size = buf->use + len;
449         size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
450     }
451 
452     if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
453         /*
454 	 * Used to provide parsing limits
455 	 */
456         if ((buf->use + len + 1 >= XML_MAX_TEXT_LENGTH) ||
457 	    (buf->size >= XML_MAX_TEXT_LENGTH)) {
458 	    xmlBufMemoryError(buf, "buffer error: text too long\n");
459 	    return(0);
460 	}
461 	if (size >= XML_MAX_TEXT_LENGTH)
462 	    size = XML_MAX_TEXT_LENGTH;
463     }
464     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
465         size_t start_buf = buf->content - buf->contentIO;
466 
467 	newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
468 	if (newbuf == NULL) {
469 	    xmlBufMemoryError(buf, "growing buffer");
470 	    return(0);
471 	}
472 	buf->contentIO = newbuf;
473 	buf->content = newbuf + start_buf;
474     } else {
475 	newbuf = (xmlChar *) xmlRealloc(buf->content, size);
476 	if (newbuf == NULL) {
477 	    xmlBufMemoryError(buf, "growing buffer");
478 	    return(0);
479 	}
480 	buf->content = newbuf;
481     }
482     buf->size = size;
483     UPDATE_COMPAT(buf)
484     return(buf->size - buf->use - 1);
485 }
486 
487 /**
488  * xmlBufGrow:
489  * @buf:  the buffer
490  * @len:  the minimum free size to allocate
491  *
492  * Grow the available space of an XML buffer, @len is the target value
493  * This is been kept compatible with xmlBufferGrow() as much as possible
494  *
495  * Returns -1 in case of error or the length made available otherwise
496  */
497 int
xmlBufGrow(xmlBufPtr buf,int len)498 xmlBufGrow(xmlBufPtr buf, int len) {
499     size_t ret;
500 
501     if ((buf == NULL) || (len < 0)) return(-1);
502     if (len == 0)
503         return(0);
504     ret = xmlBufGrowInternal(buf, len);
505     if (buf->error != 0)
506         return(-1);
507     return((int) ret);
508 }
509 
510 /**
511  * xmlBufDump:
512  * @file:  the file output
513  * @buf:  the buffer to dump
514  *
515  * Dumps an XML buffer to  a FILE *.
516  * Returns the number of #xmlChar written
517  */
518 size_t
xmlBufDump(FILE * file,xmlBufPtr buf)519 xmlBufDump(FILE *file, xmlBufPtr buf) {
520     size_t ret;
521 
522     if ((buf == NULL) || (buf->error != 0)) {
523 #ifdef DEBUG_BUFFER
524         xmlGenericError(xmlGenericErrorContext,
525 		"xmlBufDump: buf == NULL or in error\n");
526 #endif
527 	return(0);
528     }
529     if (buf->content == NULL) {
530 #ifdef DEBUG_BUFFER
531         xmlGenericError(xmlGenericErrorContext,
532 		"xmlBufDump: buf->content == NULL\n");
533 #endif
534 	return(0);
535     }
536     CHECK_COMPAT(buf)
537     if (file == NULL)
538 	file = stdout;
539     ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
540     return(ret);
541 }
542 
543 /**
544  * xmlBufContent:
545  * @buf:  the buffer
546  *
547  * Function to extract the content of a buffer
548  *
549  * Returns the internal content
550  */
551 
552 xmlChar *
xmlBufContent(const xmlBuf * buf)553 xmlBufContent(const xmlBuf *buf)
554 {
555     if ((!buf) || (buf->error))
556         return NULL;
557 
558     return(buf->content);
559 }
560 
561 /**
562  * xmlBufEnd:
563  * @buf:  the buffer
564  *
565  * Function to extract the end of the content of a buffer
566  *
567  * Returns the end of the internal content or NULL in case of error
568  */
569 
570 xmlChar *
xmlBufEnd(xmlBufPtr buf)571 xmlBufEnd(xmlBufPtr buf)
572 {
573     if ((!buf) || (buf->error))
574         return NULL;
575     CHECK_COMPAT(buf)
576 
577     return(&buf->content[buf->use]);
578 }
579 
580 /**
581  * xmlBufAddLen:
582  * @buf:  the buffer
583  * @len:  the size which were added at the end
584  *
585  * Sometime data may be added at the end of the buffer without
586  * using the xmlBuf APIs that is used to expand the used space
587  * and set the zero terminating at the end of the buffer
588  *
589  * Returns -1 in case of error and 0 otherwise
590  */
591 int
xmlBufAddLen(xmlBufPtr buf,size_t len)592 xmlBufAddLen(xmlBufPtr buf, size_t len) {
593     if ((buf == NULL) || (buf->error))
594         return(-1);
595     CHECK_COMPAT(buf)
596     if (len >= (buf->size - buf->use))
597         return(-1);
598     buf->use += len;
599     buf->content[buf->use] = 0;
600     UPDATE_COMPAT(buf)
601     return(0);
602 }
603 
604 /**
605  * xmlBufLength:
606  * @buf:  the buffer
607  *
608  * Function to get the length of a buffer
609  *
610  * Returns the length of data in the internal content
611  */
612 
613 size_t
xmlBufLength(const xmlBufPtr buf)614 xmlBufLength(const xmlBufPtr buf)
615 {
616     if ((!buf) || (buf->error))
617         return 0;
618     CHECK_COMPAT(buf)
619 
620     return(buf->use);
621 }
622 
623 /**
624  * xmlBufUse:
625  * @buf:  the buffer
626  *
627  * Function to get the length of a buffer
628  *
629  * Returns the length of data in the internal content
630  */
631 
632 size_t
xmlBufUse(const xmlBufPtr buf)633 xmlBufUse(const xmlBufPtr buf)
634 {
635     if ((!buf) || (buf->error))
636         return 0;
637     CHECK_COMPAT(buf)
638 
639     return(buf->use);
640 }
641 
642 /**
643  * xmlBufAvail:
644  * @buf:  the buffer
645  *
646  * Function to find how much free space is allocated but not
647  * used in the buffer. It reserves one byte for the NUL
648  * terminator character that is usually needed, so there is
649  * no need to subtract 1 from the result anymore.
650  *
651  * Returns the amount, or 0 if none or if an error occurred.
652  */
653 
654 size_t
xmlBufAvail(const xmlBufPtr buf)655 xmlBufAvail(const xmlBufPtr buf)
656 {
657     if ((!buf) || (buf->error))
658         return 0;
659     CHECK_COMPAT(buf)
660 
661     return((buf->size > buf->use) ? (buf->size - buf->use - 1) : 0);
662 }
663 
664 /**
665  * xmlBufIsEmpty:
666  * @buf:  the buffer
667  *
668  * Tell if a buffer is empty
669  *
670  * Returns 0 if no, 1 if yes and -1 in case of error
671  */
672 int
xmlBufIsEmpty(const xmlBufPtr buf)673 xmlBufIsEmpty(const xmlBufPtr buf)
674 {
675     if ((!buf) || (buf->error))
676         return(-1);
677     CHECK_COMPAT(buf)
678 
679     return(buf->use == 0);
680 }
681 
682 /**
683  * xmlBufResize:
684  * @buf:  the buffer to resize
685  * @size:  the desired size
686  *
687  * Resize a buffer to accommodate minimum size of @size.
688  *
689  * Returns  0 in case of problems, 1 otherwise
690  */
691 int
xmlBufResize(xmlBufPtr buf,size_t size)692 xmlBufResize(xmlBufPtr buf, size_t size)
693 {
694     size_t newSize;
695     xmlChar* rebuf = NULL;
696     size_t start_buf;
697 
698     if ((buf == NULL) || (buf->error))
699         return(0);
700     CHECK_COMPAT(buf)
701 
702     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
703     if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
704         /*
705 	 * Used to provide parsing limits
706 	 */
707         if (size >= XML_MAX_TEXT_LENGTH) {
708 	    xmlBufMemoryError(buf, "buffer error: text too long\n");
709 	    return(0);
710 	}
711     }
712 
713     /* Don't resize if we don't have to */
714     if (size < buf->size)
715         return 1;
716 
717     /* figure out new size */
718     switch (buf->alloc){
719 	case XML_BUFFER_ALLOC_IO:
720 	case XML_BUFFER_ALLOC_DOUBLEIT:
721 	    /*take care of empty case*/
722             if (buf->size == 0) {
723                 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
724             } else {
725                 newSize = buf->size;
726             }
727 	    while (size > newSize) {
728 	        if (newSize > SIZE_MAX / 2) {
729 	            xmlBufMemoryError(buf, "growing buffer");
730 	            return 0;
731 	        }
732 	        newSize *= 2;
733 	    }
734 	    break;
735 	case XML_BUFFER_ALLOC_EXACT:
736             newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
737 	    break;
738         case XML_BUFFER_ALLOC_HYBRID:
739             if (buf->use < BASE_BUFFER_SIZE)
740                 newSize = size;
741             else {
742                 newSize = buf->size;
743                 while (size > newSize) {
744                     if (newSize > SIZE_MAX / 2) {
745                         xmlBufMemoryError(buf, "growing buffer");
746                         return 0;
747                     }
748                     newSize *= 2;
749                 }
750             }
751             break;
752 
753 	default:
754             newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
755 	    break;
756     }
757 
758     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
759         start_buf = buf->content - buf->contentIO;
760 
761         if (start_buf > newSize) {
762 	    /* move data back to start */
763 	    memmove(buf->contentIO, buf->content, buf->use);
764 	    buf->content = buf->contentIO;
765 	    buf->content[buf->use] = 0;
766 	    buf->size += start_buf;
767 	} else {
768 	    rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
769 	    if (rebuf == NULL) {
770 		xmlBufMemoryError(buf, "growing buffer");
771 		return 0;
772 	    }
773 	    buf->contentIO = rebuf;
774 	    buf->content = rebuf + start_buf;
775 	}
776     } else {
777 	if (buf->content == NULL) {
778 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
779 	    buf->use = 0;
780 	    rebuf[buf->use] = 0;
781 	} else if (buf->size - buf->use < 100) {
782 	    rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
783         } else {
784 	    /*
785 	     * if we are reallocating a buffer far from being full, it's
786 	     * better to make a new allocation and copy only the used range
787 	     * and free the old one.
788 	     */
789 	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
790 	    if (rebuf != NULL) {
791 		memcpy(rebuf, buf->content, buf->use);
792 		xmlFree(buf->content);
793 		rebuf[buf->use] = 0;
794 	    }
795 	}
796 	if (rebuf == NULL) {
797 	    xmlBufMemoryError(buf, "growing buffer");
798 	    return 0;
799 	}
800 	buf->content = rebuf;
801     }
802     buf->size = newSize;
803     UPDATE_COMPAT(buf)
804 
805     return 1;
806 }
807 
808 /**
809  * xmlBufAdd:
810  * @buf:  the buffer to dump
811  * @str:  the #xmlChar string
812  * @len:  the number of #xmlChar to add
813  *
814  * Add a string range to an XML buffer. if len == -1, the length of
815  * str is recomputed.
816  *
817  * Returns 0 successful, a positive error code number otherwise
818  *         and -1 in case of internal or API error.
819  */
820 int
xmlBufAdd(xmlBufPtr buf,const xmlChar * str,int len)821 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
822     size_t needSize;
823 
824     if ((str == NULL) || (buf == NULL) || (buf->error))
825 	return -1;
826     CHECK_COMPAT(buf)
827 
828     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
829     if (len < -1) {
830 #ifdef DEBUG_BUFFER
831         xmlGenericError(xmlGenericErrorContext,
832 		"xmlBufAdd: len < 0\n");
833 #endif
834 	return -1;
835     }
836     if (len == 0) return 0;
837 
838     if (len < 0)
839         len = xmlStrlen(str);
840 
841     if (len < 0) return -1;
842     if (len == 0) return 0;
843 
844     /* Note that both buf->size and buf->use can be zero here. */
845     if ((size_t) len >= buf->size - buf->use) {
846         if ((size_t) len >= SIZE_MAX - buf->use) {
847             xmlBufMemoryError(buf, "growing buffer past SIZE_MAX");
848             return(-1);
849         }
850         needSize = buf->use + len + 1;
851 	if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
852 	    /*
853 	     * Used to provide parsing limits
854 	     */
855 	    if (needSize >= XML_MAX_TEXT_LENGTH) {
856 		xmlBufMemoryError(buf, "buffer error: text too long\n");
857 		return(-1);
858 	    }
859 	}
860         if (!xmlBufResize(buf, needSize)){
861 	    xmlBufMemoryError(buf, "growing buffer");
862             return XML_ERR_NO_MEMORY;
863         }
864     }
865 
866     memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
867     buf->use += len;
868     buf->content[buf->use] = 0;
869     UPDATE_COMPAT(buf)
870     return 0;
871 }
872 
873 /**
874  * xmlBufCat:
875  * @buf:  the buffer to add to
876  * @str:  the #xmlChar string
877  *
878  * Append a zero terminated string to an XML buffer.
879  *
880  * Returns 0 successful, a positive error code number otherwise
881  *         and -1 in case of internal or API error.
882  */
883 int
xmlBufCat(xmlBufPtr buf,const xmlChar * str)884 xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
885     if ((buf == NULL) || (buf->error))
886         return(-1);
887     CHECK_COMPAT(buf)
888     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
889     if (str == NULL) return -1;
890     return xmlBufAdd(buf, str, -1);
891 }
892 
893 /**
894  * xmlBufCCat:
895  * @buf:  the buffer to dump
896  * @str:  the C char string
897  *
898  * Append a zero terminated C string to an XML buffer.
899  *
900  * Returns 0 successful, a positive error code number otherwise
901  *         and -1 in case of internal or API error.
902  */
903 int
xmlBufCCat(xmlBufPtr buf,const char * str)904 xmlBufCCat(xmlBufPtr buf, const char *str) {
905     return xmlBufCat(buf, (const xmlChar *) str);
906 }
907 
908 /**
909  * xmlBufWriteQuotedString:
910  * @buf:  the XML buffer output
911  * @string:  the string to add
912  *
913  * routine which manage and grows an output buffer. This one writes
914  * a quoted or double quoted #xmlChar string, checking first if it holds
915  * quote or double-quotes internally
916  *
917  * Returns 0 if successful, a positive error code number otherwise
918  *         and -1 in case of internal or API error.
919  */
920 int
xmlBufWriteQuotedString(xmlBufPtr buf,const xmlChar * string)921 xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
922     const xmlChar *cur, *base;
923     if ((buf == NULL) || (buf->error))
924         return(-1);
925     CHECK_COMPAT(buf)
926     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
927         return(-1);
928     if (xmlStrchr(string, '\"')) {
929         if (xmlStrchr(string, '\'')) {
930 #ifdef DEBUG_BUFFER
931 	    xmlGenericError(xmlGenericErrorContext,
932  "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
933 #endif
934 	    xmlBufCCat(buf, "\"");
935             base = cur = string;
936             while(*cur != 0){
937                 if(*cur == '"'){
938                     if (base != cur)
939                         xmlBufAdd(buf, base, cur - base);
940                     xmlBufAdd(buf, BAD_CAST "&quot;", 6);
941                     cur++;
942                     base = cur;
943                 }
944                 else {
945                     cur++;
946                 }
947             }
948             if (base != cur)
949                 xmlBufAdd(buf, base, cur - base);
950 	    xmlBufCCat(buf, "\"");
951 	}
952         else{
953 	    xmlBufCCat(buf, "\'");
954             xmlBufCat(buf, string);
955 	    xmlBufCCat(buf, "\'");
956         }
957     } else {
958         xmlBufCCat(buf, "\"");
959         xmlBufCat(buf, string);
960         xmlBufCCat(buf, "\"");
961     }
962     return(0);
963 }
964 
965 /**
966  * xmlBufFromBuffer:
967  * @buffer: incoming old buffer to convert to a new one
968  *
969  * Helper routine to switch from the old buffer structures in use
970  * in various APIs. It creates a wrapper xmlBufPtr which will be
971  * used for internal processing until the xmlBufBackToBuffer() is
972  * issued.
973  *
974  * Returns a new xmlBufPtr unless the call failed and NULL is returned
975  */
976 xmlBufPtr
xmlBufFromBuffer(xmlBufferPtr buffer)977 xmlBufFromBuffer(xmlBufferPtr buffer) {
978     xmlBufPtr ret;
979 
980     if (buffer == NULL)
981         return(NULL);
982 
983     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
984     if (ret == NULL) {
985 	xmlBufMemoryError(NULL, "creating buffer");
986         return(NULL);
987     }
988     ret->use = buffer->use;
989     ret->size = buffer->size;
990     UPDATE_COMPAT(ret);
991     ret->error = 0;
992     ret->buffer = buffer;
993     ret->alloc = buffer->alloc;
994     ret->content = buffer->content;
995     ret->contentIO = buffer->contentIO;
996 
997     return(ret);
998 }
999 
1000 /**
1001  * xmlBufBackToBuffer:
1002  * @buf: new buffer wrapping the old one
1003  *
1004  * Function to be called once internal processing had been done to
1005  * update back the buffer provided by the user. This can lead to
1006  * a failure in case the size accumulated in the xmlBuf is larger
1007  * than what an xmlBuffer can support on 64 bits (INT_MAX)
1008  * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
1009  *
1010  * Returns the old xmlBufferPtr unless the call failed and NULL is returned
1011  */
1012 xmlBufferPtr
xmlBufBackToBuffer(xmlBufPtr buf)1013 xmlBufBackToBuffer(xmlBufPtr buf) {
1014     xmlBufferPtr ret;
1015 
1016     if (buf == NULL)
1017         return(NULL);
1018     CHECK_COMPAT(buf)
1019     if ((buf->error) || (buf->buffer == NULL)) {
1020         xmlBufFree(buf);
1021         return(NULL);
1022     }
1023 
1024     ret = buf->buffer;
1025     /*
1026      * What to do in case of error in the buffer ???
1027      */
1028     if (buf->use > INT_MAX) {
1029         /*
1030          * Worse case, we really allocated and used more than the
1031          * maximum allowed memory for an xmlBuffer on this architecture.
1032          * Keep the buffer but provide a truncated size value.
1033          */
1034         xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
1035         ret->use = INT_MAX;
1036         ret->size = INT_MAX;
1037     } else if (buf->size > INT_MAX) {
1038         /*
1039          * milder case, we allocated more than the maximum allowed memory
1040          * for an xmlBuffer on this architecture, but used less than the
1041          * limit.
1042          * Keep the buffer but provide a truncated size value.
1043          */
1044         xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
1045         ret->use = (int) buf->use;
1046         ret->size = INT_MAX;
1047     } else {
1048         ret->use = (int) buf->use;
1049         ret->size = (int) buf->size;
1050     }
1051     ret->alloc = buf->alloc;
1052     ret->content = buf->content;
1053     ret->contentIO = buf->contentIO;
1054     xmlFree(buf);
1055     return(ret);
1056 }
1057 
1058 /**
1059  * xmlBufMergeBuffer:
1060  * @buf: an xmlBufPtr
1061  * @buffer: the buffer to consume into @buf
1062  *
1063  * The content of @buffer is appended to @buf and @buffer is freed
1064  *
1065  * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
1066  */
1067 int
xmlBufMergeBuffer(xmlBufPtr buf,xmlBufferPtr buffer)1068 xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
1069     int ret = 0;
1070 
1071     if ((buf == NULL) || (buf->error)) {
1072 	xmlBufferFree(buffer);
1073         return(-1);
1074     }
1075     CHECK_COMPAT(buf)
1076     if ((buffer != NULL) && (buffer->content != NULL) &&
1077              (buffer->use > 0)) {
1078         ret = xmlBufAdd(buf, buffer->content, buffer->use);
1079     }
1080     xmlBufferFree(buffer);
1081     return(ret);
1082 }
1083 
1084 /**
1085  * xmlBufResetInput:
1086  * @buf: an xmlBufPtr
1087  * @input: an xmlParserInputPtr
1088  *
1089  * Update the input to use the current set of pointers from the buffer.
1090  *
1091  * Returns -1 in case of error, 0 otherwise
1092  */
1093 int
xmlBufResetInput(xmlBufPtr buf,xmlParserInputPtr input)1094 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
1095     if ((input == NULL) || (buf == NULL) || (buf->error))
1096         return(-1);
1097     CHECK_COMPAT(buf)
1098     input->base = input->cur = buf->content;
1099     input->end = &buf->content[buf->use];
1100     return(0);
1101 }
1102 
1103 /**
1104  * xmlBufGetInputBase:
1105  * @buf: an xmlBufPtr
1106  * @input: an xmlParserInputPtr
1107  *
1108  * Get the base of the @input relative to the beginning of the buffer
1109  *
1110  * Returns the size_t corresponding to the displacement
1111  */
1112 size_t
xmlBufGetInputBase(xmlBufPtr buf,xmlParserInputPtr input)1113 xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
1114     size_t base;
1115 
1116     if ((input == NULL) || (buf == NULL) || (buf->error))
1117         return(-1);
1118     CHECK_COMPAT(buf)
1119     base = input->base - buf->content;
1120     /*
1121      * We could do some pointer arithmetic checks but that's probably
1122      * sufficient.
1123      */
1124     if (base > buf->size) {
1125         xmlBufOverflowError(buf, "Input reference outside of the buffer");
1126         base = 0;
1127     }
1128     return(base);
1129 }
1130 
1131 /**
1132  * xmlBufSetInputBaseCur:
1133  * @buf: an xmlBufPtr
1134  * @input: an xmlParserInputPtr
1135  * @base: the base value relative to the beginning of the buffer
1136  * @cur: the cur value relative to the beginning of the buffer
1137  *
1138  * Update the input to use the base and cur relative to the buffer
1139  * after a possible reallocation of its content
1140  *
1141  * Returns -1 in case of error, 0 otherwise
1142  */
1143 int
xmlBufSetInputBaseCur(xmlBufPtr buf,xmlParserInputPtr input,size_t base,size_t cur)1144 xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
1145                       size_t base, size_t cur) {
1146     if (input == NULL)
1147         return(-1);
1148     if ((buf == NULL) || (buf->error)) {
1149         input->base = input->cur = input->end = BAD_CAST "";
1150         return(-1);
1151     }
1152     CHECK_COMPAT(buf)
1153     input->base = &buf->content[base];
1154     input->cur = input->base + cur;
1155     input->end = &buf->content[buf->use];
1156     return(0);
1157 }
1158 
1159