winemac: Directly use win32u for user functions in window.c.
[wine.git] / libs / xml2 / buf.c
blob40a5ee068b1a32a32ad0336e4b0be3f9aa23fa24
1 /*
2 * buf.c: memory buffers for libxml2
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
10 * See Copyright for the status of this software.
12 * daniel@veillard.com
15 #define IN_LIBXML
16 #include "libxml.h"
18 #include <string.h> /* for memset() only ! */
19 #include <limits.h>
20 #ifdef HAVE_CTYPE_H
21 #include <ctype.h>
22 #endif
23 #ifdef HAVE_STDLIB_H
24 #include <stdlib.h>
25 #endif
27 #include <libxml/tree.h>
28 #include <libxml/globals.h>
29 #include <libxml/tree.h>
30 #include <libxml/parserInternals.h> /* for XML_MAX_TEXT_LENGTH */
31 #include "buf.h"
33 #ifndef SIZE_MAX
34 #define SIZE_MAX ((size_t) -1)
35 #endif
37 #define WITH_BUFFER_COMPAT
39 /**
40 * xmlBuf:
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.
47 struct _xmlBuf {
48 xmlChar *content; /* The buffer content UTF8 */
49 unsigned int compat_use; /* for binary compatibility */
50 unsigned int compat_size; /* for binary compatibility */
51 xmlBufferAllocationScheme alloc; /* The realloc method */
52 xmlChar *contentIO; /* in IO mode we may have a different base */
53 size_t use; /* The buffer size used */
54 size_t size; /* The buffer size */
55 xmlBufferPtr buffer; /* wrapper for an old buffer */
56 int error; /* an error code if a failure occurred */
59 #ifdef WITH_BUFFER_COMPAT
61 * Macro for compatibility with xmlBuffer to be used after an xmlBuf
62 * is updated. This makes sure the compat fields are updated too.
64 #define UPDATE_COMPAT(buf) \
65 if (buf->size < INT_MAX) buf->compat_size = buf->size; \
66 else buf->compat_size = INT_MAX; \
67 if (buf->use < INT_MAX) buf->compat_use = buf->use; \
68 else buf->compat_use = INT_MAX;
71 * Macro for compatibility with xmlBuffer to be used in all the xmlBuf
72 * entry points, it checks that the compat fields have not been modified
73 * by direct call to xmlBuffer function from code compiled before 2.9.0 .
75 #define CHECK_COMPAT(buf) \
76 if (buf->size != (size_t) buf->compat_size) \
77 if (buf->compat_size < INT_MAX) \
78 buf->size = buf->compat_size; \
79 if (buf->use != (size_t) buf->compat_use) \
80 if (buf->compat_use < INT_MAX) \
81 buf->use = buf->compat_use;
83 #else /* ! WITH_BUFFER_COMPAT */
84 #define UPDATE_COMPAT(buf)
85 #define CHECK_COMPAT(buf)
86 #endif /* WITH_BUFFER_COMPAT */
88 /**
89 * xmlBufMemoryError:
90 * @extra: extra information
92 * Handle an out of memory condition
93 * To be improved...
95 static void
96 xmlBufMemoryError(xmlBufPtr buf, const char *extra)
98 __xmlSimpleError(XML_FROM_BUFFER, XML_ERR_NO_MEMORY, NULL, NULL, extra);
99 if ((buf) && (buf->error == 0))
100 buf->error = XML_ERR_NO_MEMORY;
104 * xmlBufOverflowError:
105 * @extra: extra information
107 * Handle a buffer overflow error
108 * To be improved...
110 static void
111 xmlBufOverflowError(xmlBufPtr buf, const char *extra)
113 __xmlSimpleError(XML_FROM_BUFFER, XML_BUF_OVERFLOW, NULL, NULL, extra);
114 if ((buf) && (buf->error == 0))
115 buf->error = XML_BUF_OVERFLOW;
120 * xmlBufCreate:
122 * routine to create an XML buffer.
123 * returns the new structure.
125 xmlBufPtr
126 xmlBufCreate(void) {
127 xmlBufPtr ret;
129 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
130 if (ret == NULL) {
131 xmlBufMemoryError(NULL, "creating buffer");
132 return(NULL);
134 ret->compat_use = 0;
135 ret->use = 0;
136 ret->error = 0;
137 ret->buffer = NULL;
138 ret->size = xmlDefaultBufferSize;
139 ret->compat_size = xmlDefaultBufferSize;
140 ret->alloc = xmlBufferAllocScheme;
141 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
142 if (ret->content == NULL) {
143 xmlBufMemoryError(ret, "creating buffer");
144 xmlFree(ret);
145 return(NULL);
147 ret->content[0] = 0;
148 ret->contentIO = NULL;
149 return(ret);
153 * xmlBufCreateSize:
154 * @size: initial size of buffer
156 * routine to create an XML buffer.
157 * returns the new structure.
159 xmlBufPtr
160 xmlBufCreateSize(size_t size) {
161 xmlBufPtr ret;
163 if (size == SIZE_MAX)
164 return(NULL);
165 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
166 if (ret == NULL) {
167 xmlBufMemoryError(NULL, "creating buffer");
168 return(NULL);
170 ret->compat_use = 0;
171 ret->use = 0;
172 ret->error = 0;
173 ret->buffer = NULL;
174 ret->alloc = xmlBufferAllocScheme;
175 ret->size = (size ? size + 1 : 0); /* +1 for ending null */
176 ret->compat_size = (ret->size > INT_MAX ? INT_MAX : ret->size);
177 if (ret->size){
178 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
179 if (ret->content == NULL) {
180 xmlBufMemoryError(ret, "creating buffer");
181 xmlFree(ret);
182 return(NULL);
184 ret->content[0] = 0;
185 } else
186 ret->content = NULL;
187 ret->contentIO = NULL;
188 return(ret);
192 * xmlBufDetach:
193 * @buf: the buffer
195 * Remove the string contained in a buffer and give it back to the
196 * caller. The buffer is reset to an empty content.
197 * This doesn't work with immutable buffers as they can't be reset.
199 * Returns the previous string contained by the buffer.
201 xmlChar *
202 xmlBufDetach(xmlBufPtr buf) {
203 xmlChar *ret;
205 if (buf == NULL)
206 return(NULL);
207 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
208 return(NULL);
209 if (buf->buffer != NULL)
210 return(NULL);
211 if (buf->error)
212 return(NULL);
214 ret = buf->content;
215 buf->content = NULL;
216 buf->size = 0;
217 buf->use = 0;
218 buf->compat_use = 0;
219 buf->compat_size = 0;
221 return ret;
226 * xmlBufCreateStatic:
227 * @mem: the memory area
228 * @size: the size in byte
230 * routine to create an XML buffer from an immutable memory area.
231 * The area won't be modified nor copied, and is expected to be
232 * present until the end of the buffer lifetime.
234 * returns the new structure.
236 xmlBufPtr
237 xmlBufCreateStatic(void *mem, size_t size) {
238 xmlBufPtr ret;
240 if (mem == NULL)
241 return(NULL);
243 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
244 if (ret == NULL) {
245 xmlBufMemoryError(NULL, "creating buffer");
246 return(NULL);
248 if (size < INT_MAX) {
249 ret->compat_use = size;
250 ret->compat_size = size;
251 } else {
252 ret->compat_use = INT_MAX;
253 ret->compat_size = INT_MAX;
255 ret->use = size;
256 ret->size = size;
257 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
258 ret->content = (xmlChar *) mem;
259 ret->error = 0;
260 ret->buffer = NULL;
261 return(ret);
265 * xmlBufGetAllocationScheme:
266 * @buf: the buffer
268 * Get the buffer allocation scheme
270 * Returns the scheme or -1 in case of error
273 xmlBufGetAllocationScheme(xmlBufPtr buf) {
274 if (buf == NULL) {
275 #ifdef DEBUG_BUFFER
276 xmlGenericError(xmlGenericErrorContext,
277 "xmlBufGetAllocationScheme: buf == NULL\n");
278 #endif
279 return(-1);
281 return(buf->alloc);
285 * xmlBufSetAllocationScheme:
286 * @buf: the buffer to tune
287 * @scheme: allocation scheme to use
289 * Sets the allocation scheme for this buffer
291 * returns 0 in case of success and -1 in case of failure
294 xmlBufSetAllocationScheme(xmlBufPtr buf,
295 xmlBufferAllocationScheme scheme) {
296 if ((buf == NULL) || (buf->error != 0)) {
297 #ifdef DEBUG_BUFFER
298 xmlGenericError(xmlGenericErrorContext,
299 "xmlBufSetAllocationScheme: buf == NULL or in error\n");
300 #endif
301 return(-1);
303 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
304 (buf->alloc == XML_BUFFER_ALLOC_IO))
305 return(-1);
306 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
307 (scheme == XML_BUFFER_ALLOC_EXACT) ||
308 (scheme == XML_BUFFER_ALLOC_HYBRID) ||
309 (scheme == XML_BUFFER_ALLOC_IMMUTABLE) ||
310 (scheme == XML_BUFFER_ALLOC_BOUNDED)) {
311 buf->alloc = scheme;
312 if (buf->buffer)
313 buf->buffer->alloc = scheme;
314 return(0);
317 * Switching a buffer ALLOC_IO has the side effect of initializing
318 * the contentIO field with the current content
320 if (scheme == XML_BUFFER_ALLOC_IO) {
321 buf->alloc = XML_BUFFER_ALLOC_IO;
322 buf->contentIO = buf->content;
324 return(-1);
328 * xmlBufFree:
329 * @buf: the buffer to free
331 * Frees an XML buffer. It frees both the content and the structure which
332 * encapsulate it.
334 void
335 xmlBufFree(xmlBufPtr buf) {
336 if (buf == NULL) {
337 #ifdef DEBUG_BUFFER
338 xmlGenericError(xmlGenericErrorContext,
339 "xmlBufFree: buf == NULL\n");
340 #endif
341 return;
344 if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
345 (buf->contentIO != NULL)) {
346 xmlFree(buf->contentIO);
347 } else if ((buf->content != NULL) &&
348 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
349 xmlFree(buf->content);
351 xmlFree(buf);
355 * xmlBufEmpty:
356 * @buf: the buffer
358 * empty a buffer.
360 void
361 xmlBufEmpty(xmlBufPtr buf) {
362 if ((buf == NULL) || (buf->error != 0)) return;
363 if (buf->content == NULL) return;
364 CHECK_COMPAT(buf)
365 buf->use = 0;
366 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
367 buf->content = BAD_CAST "";
368 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
369 (buf->contentIO != NULL)) {
370 size_t start_buf = buf->content - buf->contentIO;
372 buf->size += start_buf;
373 buf->content = buf->contentIO;
374 buf->content[0] = 0;
375 } else {
376 buf->content[0] = 0;
378 UPDATE_COMPAT(buf)
382 * xmlBufShrink:
383 * @buf: the buffer to dump
384 * @len: the number of xmlChar to remove
386 * Remove the beginning of an XML buffer.
387 * NOTE that this routine behaviour differs from xmlBufferShrink()
388 * as it will return 0 on error instead of -1 due to size_t being
389 * used as the return type.
391 * Returns the number of byte removed or 0 in case of failure
393 size_t
394 xmlBufShrink(xmlBufPtr buf, size_t len) {
395 if ((buf == NULL) || (buf->error != 0)) return(0);
396 CHECK_COMPAT(buf)
397 if (len == 0) return(0);
398 if (len > buf->use) return(0);
400 buf->use -= len;
401 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
402 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
404 * we just move the content pointer, but also make sure
405 * the perceived buffer size has shrunk accordingly
407 buf->content += len;
408 buf->size -= len;
411 * sometimes though it maybe be better to really shrink
412 * on IO buffers
414 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
415 size_t start_buf = buf->content - buf->contentIO;
416 if (start_buf >= buf->size) {
417 memmove(buf->contentIO, &buf->content[0], buf->use);
418 buf->content = buf->contentIO;
419 buf->content[buf->use] = 0;
420 buf->size += start_buf;
423 } else {
424 memmove(buf->content, &buf->content[len], buf->use);
425 buf->content[buf->use] = 0;
427 UPDATE_COMPAT(buf)
428 return(len);
432 * xmlBufGrowInternal:
433 * @buf: the buffer
434 * @len: the minimum free size to allocate
436 * Grow the available space of an XML buffer, @len is the target value
437 * Error checking should be done on buf->error since using the return
438 * value doesn't work that well
440 * Returns 0 in case of error or the length made available otherwise
442 static size_t
443 xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
444 size_t size;
445 xmlChar *newbuf;
447 if ((buf == NULL) || (buf->error != 0)) return(0);
448 CHECK_COMPAT(buf)
450 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
451 if (len < buf->size - buf->use)
452 return(buf->size - buf->use);
453 if (len > SIZE_MAX - buf->use)
454 return(0);
456 if (buf->size > (size_t) len) {
457 size = buf->size > SIZE_MAX / 2 ? SIZE_MAX : buf->size * 2;
458 } else {
459 size = buf->use + len;
460 size = size > SIZE_MAX - 100 ? SIZE_MAX : size + 100;
463 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
465 * Used to provide parsing limits
467 if ((buf->use + len >= XML_MAX_TEXT_LENGTH) ||
468 (buf->size >= XML_MAX_TEXT_LENGTH)) {
469 xmlBufMemoryError(buf, "buffer error: text too long\n");
470 return(0);
472 if (size >= XML_MAX_TEXT_LENGTH)
473 size = XML_MAX_TEXT_LENGTH;
475 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
476 size_t start_buf = buf->content - buf->contentIO;
478 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
479 if (newbuf == NULL) {
480 xmlBufMemoryError(buf, "growing buffer");
481 return(0);
483 buf->contentIO = newbuf;
484 buf->content = newbuf + start_buf;
485 } else {
486 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
487 if (newbuf == NULL) {
488 xmlBufMemoryError(buf, "growing buffer");
489 return(0);
491 buf->content = newbuf;
493 buf->size = size;
494 UPDATE_COMPAT(buf)
495 return(buf->size - buf->use);
499 * xmlBufGrow:
500 * @buf: the buffer
501 * @len: the minimum free size to allocate
503 * Grow the available space of an XML buffer, @len is the target value
504 * This is been kept compatible with xmlBufferGrow() as much as possible
506 * Returns -1 in case of error or the length made available otherwise
509 xmlBufGrow(xmlBufPtr buf, int len) {
510 size_t ret;
512 if ((buf == NULL) || (len < 0)) return(-1);
513 if (len == 0)
514 return(0);
515 ret = xmlBufGrowInternal(buf, len);
516 if (buf->error != 0)
517 return(-1);
518 return((int) ret);
522 * xmlBufInflate:
523 * @buf: the buffer
524 * @len: the minimum extra free size to allocate
526 * Grow the available space of an XML buffer, adding at least @len bytes
528 * Returns 0 if successful or -1 in case of error
531 xmlBufInflate(xmlBufPtr buf, size_t len) {
532 if (buf == NULL) return(-1);
533 xmlBufGrowInternal(buf, len + buf->size);
534 if (buf->error)
535 return(-1);
536 return(0);
540 * xmlBufDump:
541 * @file: the file output
542 * @buf: the buffer to dump
544 * Dumps an XML buffer to a FILE *.
545 * Returns the number of #xmlChar written
547 size_t
548 xmlBufDump(FILE *file, xmlBufPtr buf) {
549 size_t ret;
551 if ((buf == NULL) || (buf->error != 0)) {
552 #ifdef DEBUG_BUFFER
553 xmlGenericError(xmlGenericErrorContext,
554 "xmlBufDump: buf == NULL or in error\n");
555 #endif
556 return(0);
558 if (buf->content == NULL) {
559 #ifdef DEBUG_BUFFER
560 xmlGenericError(xmlGenericErrorContext,
561 "xmlBufDump: buf->content == NULL\n");
562 #endif
563 return(0);
565 CHECK_COMPAT(buf)
566 if (file == NULL)
567 file = stdout;
568 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
569 return(ret);
573 * xmlBufContent:
574 * @buf: the buffer
576 * Function to extract the content of a buffer
578 * Returns the internal content
581 xmlChar *
582 xmlBufContent(const xmlBuf *buf)
584 if ((!buf) || (buf->error))
585 return NULL;
587 return(buf->content);
591 * xmlBufEnd:
592 * @buf: the buffer
594 * Function to extract the end of the content of a buffer
596 * Returns the end of the internal content or NULL in case of error
599 xmlChar *
600 xmlBufEnd(xmlBufPtr buf)
602 if ((!buf) || (buf->error))
603 return NULL;
604 CHECK_COMPAT(buf)
606 return(&buf->content[buf->use]);
610 * xmlBufAddLen:
611 * @buf: the buffer
612 * @len: the size which were added at the end
614 * Sometime data may be added at the end of the buffer without
615 * using the xmlBuf APIs that is used to expand the used space
616 * and set the zero terminating at the end of the buffer
618 * Returns -1 in case of error and 0 otherwise
621 xmlBufAddLen(xmlBufPtr buf, size_t len) {
622 if ((buf == NULL) || (buf->error))
623 return(-1);
624 CHECK_COMPAT(buf)
625 if (len > (buf->size - buf->use))
626 return(-1);
627 buf->use += len;
628 UPDATE_COMPAT(buf)
629 if (buf->size > buf->use)
630 buf->content[buf->use] = 0;
631 else
632 return(-1);
633 return(0);
637 * xmlBufErase:
638 * @buf: the buffer
639 * @len: the size to erase at the end
641 * Sometime data need to be erased at the end of the buffer
643 * Returns -1 in case of error and 0 otherwise
646 xmlBufErase(xmlBufPtr buf, size_t len) {
647 if ((buf == NULL) || (buf->error))
648 return(-1);
649 CHECK_COMPAT(buf)
650 if (len > buf->use)
651 return(-1);
652 buf->use -= len;
653 buf->content[buf->use] = 0;
654 UPDATE_COMPAT(buf)
655 return(0);
659 * xmlBufLength:
660 * @buf: the buffer
662 * Function to get the length of a buffer
664 * Returns the length of data in the internal content
667 size_t
668 xmlBufLength(const xmlBufPtr buf)
670 if ((!buf) || (buf->error))
671 return 0;
672 CHECK_COMPAT(buf)
674 return(buf->use);
678 * xmlBufUse:
679 * @buf: the buffer
681 * Function to get the length of a buffer
683 * Returns the length of data in the internal content
686 size_t
687 xmlBufUse(const xmlBufPtr buf)
689 if ((!buf) || (buf->error))
690 return 0;
691 CHECK_COMPAT(buf)
693 return(buf->use);
697 * xmlBufAvail:
698 * @buf: the buffer
700 * Function to find how much free space is allocated but not
701 * used in the buffer. It does not account for the terminating zero
702 * usually needed
704 * Returns the amount or 0 if none or an error occurred
707 size_t
708 xmlBufAvail(const xmlBufPtr buf)
710 if ((!buf) || (buf->error))
711 return 0;
712 CHECK_COMPAT(buf)
714 return(buf->size - buf->use);
718 * xmlBufIsEmpty:
719 * @buf: the buffer
721 * Tell if a buffer is empty
723 * Returns 0 if no, 1 if yes and -1 in case of error
726 xmlBufIsEmpty(const xmlBufPtr buf)
728 if ((!buf) || (buf->error))
729 return(-1);
730 CHECK_COMPAT(buf)
732 return(buf->use == 0);
736 * xmlBufResize:
737 * @buf: the buffer to resize
738 * @size: the desired size
740 * Resize a buffer to accommodate minimum size of @size.
742 * Returns 0 in case of problems, 1 otherwise
745 xmlBufResize(xmlBufPtr buf, size_t size)
747 size_t newSize;
748 xmlChar* rebuf = NULL;
749 size_t start_buf;
751 if ((buf == NULL) || (buf->error))
752 return(0);
753 CHECK_COMPAT(buf)
755 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
756 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
758 * Used to provide parsing limits
760 if (size >= XML_MAX_TEXT_LENGTH) {
761 xmlBufMemoryError(buf, "buffer error: text too long\n");
762 return(0);
766 /* Don't resize if we don't have to */
767 if (size < buf->size)
768 return 1;
770 /* figure out new size */
771 switch (buf->alloc){
772 case XML_BUFFER_ALLOC_IO:
773 case XML_BUFFER_ALLOC_DOUBLEIT:
774 /*take care of empty case*/
775 if (buf->size == 0) {
776 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
777 } else {
778 newSize = buf->size;
780 while (size > newSize) {
781 if (newSize > SIZE_MAX / 2) {
782 xmlBufMemoryError(buf, "growing buffer");
783 return 0;
785 newSize *= 2;
787 break;
788 case XML_BUFFER_ALLOC_EXACT:
789 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
790 break;
791 case XML_BUFFER_ALLOC_HYBRID:
792 if (buf->use < BASE_BUFFER_SIZE)
793 newSize = size;
794 else {
795 newSize = buf->size;
796 while (size > newSize) {
797 if (newSize > SIZE_MAX / 2) {
798 xmlBufMemoryError(buf, "growing buffer");
799 return 0;
801 newSize *= 2;
804 break;
806 default:
807 newSize = (size > SIZE_MAX - 10 ? SIZE_MAX : size + 10);
808 break;
811 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
812 start_buf = buf->content - buf->contentIO;
814 if (start_buf > newSize) {
815 /* move data back to start */
816 memmove(buf->contentIO, buf->content, buf->use);
817 buf->content = buf->contentIO;
818 buf->content[buf->use] = 0;
819 buf->size += start_buf;
820 } else {
821 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
822 if (rebuf == NULL) {
823 xmlBufMemoryError(buf, "growing buffer");
824 return 0;
826 buf->contentIO = rebuf;
827 buf->content = rebuf + start_buf;
829 } else {
830 if (buf->content == NULL) {
831 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
832 } else if (buf->size - buf->use < 100) {
833 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
834 } else {
836 * if we are reallocating a buffer far from being full, it's
837 * better to make a new allocation and copy only the used range
838 * and free the old one.
840 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
841 if (rebuf != NULL) {
842 memcpy(rebuf, buf->content, buf->use);
843 xmlFree(buf->content);
844 rebuf[buf->use] = 0;
847 if (rebuf == NULL) {
848 xmlBufMemoryError(buf, "growing buffer");
849 return 0;
851 buf->content = rebuf;
853 buf->size = newSize;
854 UPDATE_COMPAT(buf)
856 return 1;
860 * xmlBufAdd:
861 * @buf: the buffer to dump
862 * @str: the #xmlChar string
863 * @len: the number of #xmlChar to add
865 * Add a string range to an XML buffer. if len == -1, the length of
866 * str is recomputed.
868 * Returns 0 successful, a positive error code number otherwise
869 * and -1 in case of internal or API error.
872 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
873 size_t needSize;
875 if ((str == NULL) || (buf == NULL) || (buf->error))
876 return -1;
877 CHECK_COMPAT(buf)
879 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
880 if (len < -1) {
881 #ifdef DEBUG_BUFFER
882 xmlGenericError(xmlGenericErrorContext,
883 "xmlBufAdd: len < 0\n");
884 #endif
885 return -1;
887 if (len == 0) return 0;
889 if (len < 0)
890 len = xmlStrlen(str);
892 if (len < 0) return -1;
893 if (len == 0) return 0;
895 if ((size_t) len >= buf->size - buf->use) {
896 if ((size_t) len >= SIZE_MAX - buf->use)
897 return(-1);
898 needSize = buf->use + len + 1;
899 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
901 * Used to provide parsing limits
903 if (needSize >= XML_MAX_TEXT_LENGTH) {
904 xmlBufMemoryError(buf, "buffer error: text too long\n");
905 return(-1);
908 if (!xmlBufResize(buf, needSize)){
909 xmlBufMemoryError(buf, "growing buffer");
910 return XML_ERR_NO_MEMORY;
914 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
915 buf->use += len;
916 buf->content[buf->use] = 0;
917 UPDATE_COMPAT(buf)
918 return 0;
922 * xmlBufAddHead:
923 * @buf: the buffer
924 * @str: the #xmlChar string
925 * @len: the number of #xmlChar to add
927 * Add a string range to the beginning of an XML buffer.
928 * if len == -1, the length of @str is recomputed.
930 * Returns 0 successful, a positive error code number otherwise
931 * and -1 in case of internal or API error.
934 xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
935 unsigned int needSize;
937 if ((buf == NULL) || (buf->error))
938 return(-1);
939 CHECK_COMPAT(buf)
940 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
941 if (str == NULL) {
942 #ifdef DEBUG_BUFFER
943 xmlGenericError(xmlGenericErrorContext,
944 "xmlBufAddHead: str == NULL\n");
945 #endif
946 return -1;
948 if (len < -1) {
949 #ifdef DEBUG_BUFFER
950 xmlGenericError(xmlGenericErrorContext,
951 "xmlBufAddHead: len < 0\n");
952 #endif
953 return -1;
955 if (len == 0) return 0;
957 if (len < 0)
958 len = xmlStrlen(str);
960 if (len <= 0) return -1;
962 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
963 size_t start_buf = buf->content - buf->contentIO;
965 if (start_buf > (unsigned int) len) {
967 * We can add it in the space previously shrunk
969 buf->content -= len;
970 memmove(&buf->content[0], str, len);
971 buf->use += len;
972 buf->size += len;
973 UPDATE_COMPAT(buf)
974 return(0);
977 needSize = buf->use + len + 2;
978 if (needSize > buf->size){
979 if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
981 * Used to provide parsing limits
983 if (needSize >= XML_MAX_TEXT_LENGTH) {
984 xmlBufMemoryError(buf, "buffer error: text too long\n");
985 return(-1);
988 if (!xmlBufResize(buf, needSize)){
989 xmlBufMemoryError(buf, "growing buffer");
990 return XML_ERR_NO_MEMORY;
994 memmove(&buf->content[len], &buf->content[0], buf->use);
995 memmove(&buf->content[0], str, len);
996 buf->use += len;
997 buf->content[buf->use] = 0;
998 UPDATE_COMPAT(buf)
999 return 0;
1003 * xmlBufCat:
1004 * @buf: the buffer to add to
1005 * @str: the #xmlChar string
1007 * Append a zero terminated string to an XML buffer.
1009 * Returns 0 successful, a positive error code number otherwise
1010 * and -1 in case of internal or API error.
1013 xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
1014 if ((buf == NULL) || (buf->error))
1015 return(-1);
1016 CHECK_COMPAT(buf)
1017 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1018 if (str == NULL) return -1;
1019 return xmlBufAdd(buf, str, -1);
1023 * xmlBufCCat:
1024 * @buf: the buffer to dump
1025 * @str: the C char string
1027 * Append a zero terminated C string to an XML buffer.
1029 * Returns 0 successful, a positive error code number otherwise
1030 * and -1 in case of internal or API error.
1033 xmlBufCCat(xmlBufPtr buf, const char *str) {
1034 return xmlBufCat(buf, (const xmlChar *) str);
1038 * xmlBufWriteCHAR:
1039 * @buf: the XML buffer
1040 * @string: the string to add
1042 * routine which manages and grows an output buffer. This one adds
1043 * xmlChars at the end of the buffer.
1045 * Returns 0 if successful, a positive error code number otherwise
1046 * and -1 in case of internal or API error.
1049 xmlBufWriteCHAR(xmlBufPtr buf, const xmlChar *string) {
1050 if ((buf == NULL) || (buf->error))
1051 return(-1);
1052 CHECK_COMPAT(buf)
1053 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1054 return(-1);
1055 return(xmlBufCat(buf, string));
1059 * xmlBufWriteChar:
1060 * @buf: the XML buffer output
1061 * @string: the string to add
1063 * routine which manage and grows an output buffer. This one add
1064 * C chars at the end of the array.
1066 * Returns 0 if successful, a positive error code number otherwise
1067 * and -1 in case of internal or API error.
1070 xmlBufWriteChar(xmlBufPtr buf, const char *string) {
1071 if ((buf == NULL) || (buf->error))
1072 return(-1);
1073 CHECK_COMPAT(buf)
1074 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1075 return(-1);
1076 return(xmlBufCCat(buf, string));
1081 * xmlBufWriteQuotedString:
1082 * @buf: the XML buffer output
1083 * @string: the string to add
1085 * routine which manage and grows an output buffer. This one writes
1086 * a quoted or double quoted #xmlChar string, checking first if it holds
1087 * quote or double-quotes internally
1089 * Returns 0 if successful, a positive error code number otherwise
1090 * and -1 in case of internal or API error.
1093 xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
1094 const xmlChar *cur, *base;
1095 if ((buf == NULL) || (buf->error))
1096 return(-1);
1097 CHECK_COMPAT(buf)
1098 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1099 return(-1);
1100 if (xmlStrchr(string, '\"')) {
1101 if (xmlStrchr(string, '\'')) {
1102 #ifdef DEBUG_BUFFER
1103 xmlGenericError(xmlGenericErrorContext,
1104 "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
1105 #endif
1106 xmlBufCCat(buf, "\"");
1107 base = cur = string;
1108 while(*cur != 0){
1109 if(*cur == '"'){
1110 if (base != cur)
1111 xmlBufAdd(buf, base, cur - base);
1112 xmlBufAdd(buf, BAD_CAST "&quot;", 6);
1113 cur++;
1114 base = cur;
1116 else {
1117 cur++;
1120 if (base != cur)
1121 xmlBufAdd(buf, base, cur - base);
1122 xmlBufCCat(buf, "\"");
1124 else{
1125 xmlBufCCat(buf, "\'");
1126 xmlBufCat(buf, string);
1127 xmlBufCCat(buf, "\'");
1129 } else {
1130 xmlBufCCat(buf, "\"");
1131 xmlBufCat(buf, string);
1132 xmlBufCCat(buf, "\"");
1134 return(0);
1138 * xmlBufFromBuffer:
1139 * @buffer: incoming old buffer to convert to a new one
1141 * Helper routine to switch from the old buffer structures in use
1142 * in various APIs. It creates a wrapper xmlBufPtr which will be
1143 * used for internal processing until the xmlBufBackToBuffer() is
1144 * issued.
1146 * Returns a new xmlBufPtr unless the call failed and NULL is returned
1148 xmlBufPtr
1149 xmlBufFromBuffer(xmlBufferPtr buffer) {
1150 xmlBufPtr ret;
1152 if (buffer == NULL)
1153 return(NULL);
1155 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
1156 if (ret == NULL) {
1157 xmlBufMemoryError(NULL, "creating buffer");
1158 return(NULL);
1160 ret->use = buffer->use;
1161 ret->size = buffer->size;
1162 ret->compat_use = buffer->use;
1163 ret->compat_size = buffer->size;
1164 ret->error = 0;
1165 ret->buffer = buffer;
1166 ret->alloc = buffer->alloc;
1167 ret->content = buffer->content;
1168 ret->contentIO = buffer->contentIO;
1170 return(ret);
1174 * xmlBufBackToBuffer:
1175 * @buf: new buffer wrapping the old one
1177 * Function to be called once internal processing had been done to
1178 * update back the buffer provided by the user. This can lead to
1179 * a failure in case the size accumulated in the xmlBuf is larger
1180 * than what an xmlBuffer can support on 64 bits (INT_MAX)
1181 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
1183 * Returns the old xmlBufferPtr unless the call failed and NULL is returned
1185 xmlBufferPtr
1186 xmlBufBackToBuffer(xmlBufPtr buf) {
1187 xmlBufferPtr ret;
1189 if (buf == NULL)
1190 return(NULL);
1191 CHECK_COMPAT(buf)
1192 if ((buf->error) || (buf->buffer == NULL)) {
1193 xmlBufFree(buf);
1194 return(NULL);
1197 ret = buf->buffer;
1199 * What to do in case of error in the buffer ???
1201 if (buf->use > INT_MAX) {
1203 * Worse case, we really allocated and used more than the
1204 * maximum allowed memory for an xmlBuffer on this architecture.
1205 * Keep the buffer but provide a truncated size value.
1207 xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
1208 ret->use = INT_MAX;
1209 ret->size = INT_MAX;
1210 } else if (buf->size > INT_MAX) {
1212 * milder case, we allocated more than the maximum allowed memory
1213 * for an xmlBuffer on this architecture, but used less than the
1214 * limit.
1215 * Keep the buffer but provide a truncated size value.
1217 xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
1218 ret->use = (int) buf->use;
1219 ret->size = INT_MAX;
1220 } else {
1221 ret->use = (int) buf->use;
1222 ret->size = (int) buf->size;
1224 ret->alloc = buf->alloc;
1225 ret->content = buf->content;
1226 ret->contentIO = buf->contentIO;
1227 xmlFree(buf);
1228 return(ret);
1232 * xmlBufMergeBuffer:
1233 * @buf: an xmlBufPtr
1234 * @buffer: the buffer to consume into @buf
1236 * The content of @buffer is appended to @buf and @buffer is freed
1238 * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
1241 xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
1242 int ret = 0;
1244 if ((buf == NULL) || (buf->error)) {
1245 xmlBufferFree(buffer);
1246 return(-1);
1248 CHECK_COMPAT(buf)
1249 if ((buffer != NULL) && (buffer->content != NULL) &&
1250 (buffer->use > 0)) {
1251 ret = xmlBufAdd(buf, buffer->content, buffer->use);
1253 xmlBufferFree(buffer);
1254 return(ret);
1258 * xmlBufResetInput:
1259 * @buf: an xmlBufPtr
1260 * @input: an xmlParserInputPtr
1262 * Update the input to use the current set of pointers from the buffer.
1264 * Returns -1 in case of error, 0 otherwise
1267 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
1268 if ((input == NULL) || (buf == NULL) || (buf->error))
1269 return(-1);
1270 CHECK_COMPAT(buf)
1271 input->base = input->cur = buf->content;
1272 input->end = &buf->content[buf->use];
1273 return(0);
1277 * xmlBufGetInputBase:
1278 * @buf: an xmlBufPtr
1279 * @input: an xmlParserInputPtr
1281 * Get the base of the @input relative to the beginning of the buffer
1283 * Returns the size_t corresponding to the displacement
1285 size_t
1286 xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
1287 size_t base;
1289 if ((input == NULL) || (buf == NULL) || (buf->error))
1290 return(-1);
1291 CHECK_COMPAT(buf)
1292 base = input->base - buf->content;
1294 * We could do some pointer arithmetic checks but that's probably
1295 * sufficient.
1297 if (base > buf->size) {
1298 xmlBufOverflowError(buf, "Input reference outside of the buffer");
1299 base = 0;
1301 return(base);
1305 * xmlBufSetInputBaseCur:
1306 * @buf: an xmlBufPtr
1307 * @input: an xmlParserInputPtr
1308 * @base: the base value relative to the beginning of the buffer
1309 * @cur: the cur value relative to the beginning of the buffer
1311 * Update the input to use the base and cur relative to the buffer
1312 * after a possible reallocation of its content
1314 * Returns -1 in case of error, 0 otherwise
1317 xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
1318 size_t base, size_t cur) {
1319 if (input == NULL)
1320 return(-1);
1321 if ((buf == NULL) || (buf->error)) {
1322 input->base = input->cur = input->end = BAD_CAST "";
1323 return(-1);
1325 CHECK_COMPAT(buf)
1326 input->base = &buf->content[base];
1327 input->cur = input->base + cur;
1328 input->end = &buf->content[buf->use];
1329 return(0);
1332 #define bottom_buf
1333 #include "elfgcchack.h"