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