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