Update V8 to version 4.6.55.
[chromium-blink-merge.git] / third_party / libxml / src / buf.c
blob6efc7b677c33d3b895555c43a0988d18c97448a2
1 /*
2 * buf.c: memory buffers for libxml2
4 * new buffer structures and entry points to simplify the maintainance
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 "buf.h"
32 #define WITH_BUFFER_COMPAT
34 /**
35 * xmlBuf:
37 * A buffer structure. The base of the structure is somehow compatible
38 * with struct _xmlBuffer to limit risks on application which accessed
39 * directly the input->buf->buffer structures.
42 struct _xmlBuf {
43 xmlChar *content; /* The buffer content UTF8 */
44 unsigned int compat_use; /* for binary compatibility */
45 unsigned int compat_size; /* for binary compatibility */
46 xmlBufferAllocationScheme alloc; /* The realloc method */
47 xmlChar *contentIO; /* in IO mode we may have a different base */
48 size_t use; /* The buffer size used */
49 size_t size; /* The buffer size */
50 xmlBufferPtr buffer; /* wrapper for an old buffer */
51 int error; /* an error code if a failure occured */
54 #ifdef WITH_BUFFER_COMPAT
56 * Macro for compatibility with xmlBuffer to be used after an xmlBuf
57 * is updated. This makes sure the compat fields are updated too.
59 #define UPDATE_COMPAT(buf) \
60 if (buf->size < INT_MAX) buf->compat_size = buf->size; \
61 else buf->compat_size = INT_MAX; \
62 if (buf->use < INT_MAX) buf->compat_use = buf->use; \
63 else buf->compat_use = INT_MAX;
66 * Macro for compatibility with xmlBuffer to be used in all the xmlBuf
67 * entry points, it checks that the compat fields have not been modified
68 * by direct call to xmlBuffer function from code compiled before 2.9.0 .
70 #define CHECK_COMPAT(buf) \
71 if (buf->size != (size_t) buf->compat_size) \
72 if (buf->compat_size < INT_MAX) \
73 buf->size = buf->compat_size; \
74 if (buf->use != (size_t) buf->compat_use) \
75 if (buf->compat_use < INT_MAX) \
76 buf->use = buf->compat_use;
78 #else /* ! WITH_BUFFER_COMPAT */
79 #define UPDATE_COMPAT(buf)
80 #define CHECK_COMPAT(buf)
81 #endif /* WITH_BUFFER_COMPAT */
83 /**
84 * xmlBufMemoryError:
85 * @extra: extra informations
87 * Handle an out of memory condition
88 * To be improved...
90 static void
91 xmlBufMemoryError(xmlBufPtr buf, const char *extra)
93 __xmlSimpleError(XML_FROM_BUFFER, XML_ERR_NO_MEMORY, NULL, NULL, extra);
94 if ((buf) && (buf->error == 0))
95 buf->error = XML_ERR_NO_MEMORY;
98 /**
99 * xmlBufOverflowError:
100 * @extra: extra informations
102 * Handle a buffer overflow error
103 * To be improved...
105 static void
106 xmlBufOverflowError(xmlBufPtr buf, const char *extra)
108 __xmlSimpleError(XML_FROM_BUFFER, XML_BUF_OVERFLOW, NULL, NULL, extra);
109 if ((buf) && (buf->error == 0))
110 buf->error = XML_BUF_OVERFLOW;
115 * xmlBufCreate:
117 * routine to create an XML buffer.
118 * returns the new structure.
120 xmlBufPtr
121 xmlBufCreate(void) {
122 xmlBufPtr ret;
124 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
125 if (ret == NULL) {
126 xmlBufMemoryError(NULL, "creating buffer");
127 return(NULL);
129 ret->compat_use = 0;
130 ret->use = 0;
131 ret->error = 0;
132 ret->buffer = NULL;
133 ret->size = xmlDefaultBufferSize;
134 ret->compat_size = xmlDefaultBufferSize;
135 ret->alloc = xmlBufferAllocScheme;
136 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
137 if (ret->content == NULL) {
138 xmlBufMemoryError(ret, "creating buffer");
139 xmlFree(ret);
140 return(NULL);
142 ret->content[0] = 0;
143 ret->contentIO = NULL;
144 return(ret);
148 * xmlBufCreateSize:
149 * @size: initial size of buffer
151 * routine to create an XML buffer.
152 * returns the new structure.
154 xmlBufPtr
155 xmlBufCreateSize(size_t size) {
156 xmlBufPtr ret;
158 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
159 if (ret == NULL) {
160 xmlBufMemoryError(NULL, "creating buffer");
161 return(NULL);
163 ret->compat_use = 0;
164 ret->use = 0;
165 ret->error = 0;
166 ret->buffer = NULL;
167 ret->alloc = xmlBufferAllocScheme;
168 ret->size = (size ? size+2 : 0); /* +1 for ending null */
169 ret->compat_size = (int) ret->size;
170 if (ret->size){
171 ret->content = (xmlChar *) xmlMallocAtomic(ret->size * sizeof(xmlChar));
172 if (ret->content == NULL) {
173 xmlBufMemoryError(ret, "creating buffer");
174 xmlFree(ret);
175 return(NULL);
177 ret->content[0] = 0;
178 } else
179 ret->content = NULL;
180 ret->contentIO = NULL;
181 return(ret);
185 * xmlBufDetach:
186 * @buf: the buffer
188 * Remove the string contained in a buffer and give it back to the
189 * caller. The buffer is reset to an empty content.
190 * This doesn't work with immutable buffers as they can't be reset.
192 * Returns the previous string contained by the buffer.
194 xmlChar *
195 xmlBufDetach(xmlBufPtr buf) {
196 xmlChar *ret;
198 if (buf == NULL)
199 return(NULL);
200 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
201 return(NULL);
202 if (buf->buffer != NULL)
203 return(NULL);
204 if (buf->error)
205 return(NULL);
207 ret = buf->content;
208 buf->content = NULL;
209 buf->size = 0;
210 buf->use = 0;
211 buf->compat_use = 0;
212 buf->compat_size = 0;
214 return ret;
219 * xmlBufCreateStatic:
220 * @mem: the memory area
221 * @size: the size in byte
223 * routine to create an XML buffer from an immutable memory area.
224 * The area won't be modified nor copied, and is expected to be
225 * present until the end of the buffer lifetime.
227 * returns the new structure.
229 xmlBufPtr
230 xmlBufCreateStatic(void *mem, size_t size) {
231 xmlBufPtr ret;
233 if ((mem == NULL) || (size == 0))
234 return(NULL);
236 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
237 if (ret == NULL) {
238 xmlBufMemoryError(NULL, "creating buffer");
239 return(NULL);
241 if (size < INT_MAX) {
242 ret->compat_use = size;
243 ret->compat_size = size;
244 } else {
245 ret->compat_use = INT_MAX;
246 ret->compat_size = INT_MAX;
248 ret->use = size;
249 ret->size = size;
250 ret->alloc = XML_BUFFER_ALLOC_IMMUTABLE;
251 ret->content = (xmlChar *) mem;
252 ret->error = 0;
253 ret->buffer = NULL;
254 return(ret);
258 * xmlBufGetAllocationScheme:
259 * @buf: the buffer
261 * Get the buffer allocation scheme
263 * Returns the scheme or -1 in case of error
266 xmlBufGetAllocationScheme(xmlBufPtr buf) {
267 if (buf == NULL) {
268 #ifdef DEBUG_BUFFER
269 xmlGenericError(xmlGenericErrorContext,
270 "xmlBufGetAllocationScheme: buf == NULL\n");
271 #endif
272 return(-1);
274 return(buf->alloc);
278 * xmlBufSetAllocationScheme:
279 * @buf: the buffer to tune
280 * @scheme: allocation scheme to use
282 * Sets the allocation scheme for this buffer
284 * returns 0 in case of success and -1 in case of failure
287 xmlBufSetAllocationScheme(xmlBufPtr buf,
288 xmlBufferAllocationScheme scheme) {
289 if ((buf == NULL) || (buf->error != 0)) {
290 #ifdef DEBUG_BUFFER
291 xmlGenericError(xmlGenericErrorContext,
292 "xmlBufSetAllocationScheme: buf == NULL or in error\n");
293 #endif
294 return(-1);
296 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
297 (buf->alloc == XML_BUFFER_ALLOC_IO))
298 return(-1);
299 if ((scheme == XML_BUFFER_ALLOC_DOUBLEIT) ||
300 (scheme == XML_BUFFER_ALLOC_EXACT) ||
301 (scheme == XML_BUFFER_ALLOC_HYBRID) ||
302 (scheme == XML_BUFFER_ALLOC_IMMUTABLE)) {
303 buf->alloc = scheme;
304 if (buf->buffer)
305 buf->buffer->alloc = scheme;
306 return(0);
309 * Switching a buffer ALLOC_IO has the side effect of initializing
310 * the contentIO field with the current content
312 if (scheme == XML_BUFFER_ALLOC_IO) {
313 buf->alloc = XML_BUFFER_ALLOC_IO;
314 buf->contentIO = buf->content;
316 return(-1);
320 * xmlBufFree:
321 * @buf: the buffer to free
323 * Frees an XML buffer. It frees both the content and the structure which
324 * encapsulate it.
326 void
327 xmlBufFree(xmlBufPtr buf) {
328 if (buf == NULL) {
329 #ifdef DEBUG_BUFFER
330 xmlGenericError(xmlGenericErrorContext,
331 "xmlBufFree: buf == NULL\n");
332 #endif
333 return;
336 if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
337 (buf->contentIO != NULL)) {
338 xmlFree(buf->contentIO);
339 } else if ((buf->content != NULL) &&
340 (buf->alloc != XML_BUFFER_ALLOC_IMMUTABLE)) {
341 xmlFree(buf->content);
343 xmlFree(buf);
347 * xmlBufEmpty:
348 * @buf: the buffer
350 * empty a buffer.
352 void
353 xmlBufEmpty(xmlBufPtr buf) {
354 if ((buf == NULL) || (buf->error != 0)) return;
355 if (buf->content == NULL) return;
356 CHECK_COMPAT(buf)
357 buf->use = 0;
358 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) {
359 buf->content = BAD_CAST "";
360 } else if ((buf->alloc == XML_BUFFER_ALLOC_IO) &&
361 (buf->contentIO != NULL)) {
362 size_t start_buf = buf->content - buf->contentIO;
364 buf->size += start_buf;
365 buf->content = buf->contentIO;
366 buf->content[0] = 0;
367 } else {
368 buf->content[0] = 0;
370 UPDATE_COMPAT(buf)
374 * xmlBufShrink:
375 * @buf: the buffer to dump
376 * @len: the number of xmlChar to remove
378 * Remove the beginning of an XML buffer.
379 * NOTE that this routine behaviour differs from xmlBufferShrink()
380 * as it will return 0 on error instead of -1 due to size_t being
381 * used as the return type.
383 * Returns the number of byte removed or 0 in case of failure
385 size_t
386 xmlBufShrink(xmlBufPtr buf, size_t len) {
387 if ((buf == NULL) || (buf->error != 0)) return(0);
388 CHECK_COMPAT(buf)
389 if (len == 0) return(0);
390 if (len > buf->use) return(0);
392 buf->use -= len;
393 if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
394 ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
396 * we just move the content pointer, but also make sure
397 * the perceived buffer size has shrinked accordingly
399 buf->content += len;
400 buf->size -= len;
403 * sometimes though it maybe be better to really shrink
404 * on IO buffers
406 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
407 size_t start_buf = buf->content - buf->contentIO;
408 if (start_buf >= buf->size) {
409 memmove(buf->contentIO, &buf->content[0], buf->use);
410 buf->content = buf->contentIO;
411 buf->content[buf->use] = 0;
412 buf->size += start_buf;
415 } else {
416 memmove(buf->content, &buf->content[len], buf->use);
417 buf->content[buf->use] = 0;
419 UPDATE_COMPAT(buf)
420 return(len);
424 * xmlBufGrowInternal:
425 * @buf: the buffer
426 * @len: the minimum free size to allocate
428 * Grow the available space of an XML buffer, @len is the target value
429 * Error checking should be done on buf->error since using the return
430 * value doesn't work that well
432 * Returns 0 in case of error or the length made available otherwise
434 static size_t
435 xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
436 size_t size;
437 xmlChar *newbuf;
439 if ((buf == NULL) || (buf->error != 0)) return(0);
440 CHECK_COMPAT(buf)
442 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
443 if (buf->use + len < buf->size)
444 return(buf->size - buf->use);
447 * Windows has a BIG problem on realloc timing, so we try to double
448 * the buffer size (if that's enough) (bug 146697)
449 * Apparently BSD too, and it's probably best for linux too
450 * On an embedded system this may be something to change
452 #if 1
453 if (buf->size > (size_t) len)
454 size = buf->size * 2;
455 else
456 size = buf->use + len + 100;
457 #else
458 size = buf->use + len + 100;
459 #endif
461 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
462 size_t start_buf = buf->content - buf->contentIO;
464 newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
465 if (newbuf == NULL) {
466 xmlBufMemoryError(buf, "growing buffer");
467 return(0);
469 buf->contentIO = newbuf;
470 buf->content = newbuf + start_buf;
471 } else {
472 newbuf = (xmlChar *) xmlRealloc(buf->content, size);
473 if (newbuf == NULL) {
474 xmlBufMemoryError(buf, "growing buffer");
475 return(0);
477 buf->content = newbuf;
479 buf->size = size;
480 UPDATE_COMPAT(buf)
481 return(buf->size - buf->use);
485 * xmlBufGrow:
486 * @buf: the buffer
487 * @len: the minimum free size to allocate
489 * Grow the available space of an XML buffer, @len is the target value
490 * This is been kept compatible with xmlBufferGrow() as much as possible
492 * Returns -1 in case of error or the length made available otherwise
495 xmlBufGrow(xmlBufPtr buf, int len) {
496 size_t ret;
498 if ((buf == NULL) || (len < 0)) return(-1);
499 if (len == 0)
500 return(0);
501 ret = xmlBufGrowInternal(buf, len);
502 if (buf->error != 0)
503 return(-1);
504 return((int) ret);
508 * xmlBufInflate:
509 * @buf: the buffer
510 * @len: the minimum extra free size to allocate
512 * Grow the available space of an XML buffer, adding at least @len bytes
514 * Returns 0 if successful or -1 in case of error
517 xmlBufInflate(xmlBufPtr buf, size_t len) {
518 if (buf == NULL) return(-1);
519 xmlBufGrowInternal(buf, len + buf->size);
520 if (buf->error)
521 return(-1);
522 return(0);
526 * xmlBufDump:
527 * @file: the file output
528 * @buf: the buffer to dump
530 * Dumps an XML buffer to a FILE *.
531 * Returns the number of #xmlChar written
533 size_t
534 xmlBufDump(FILE *file, xmlBufPtr buf) {
535 size_t ret;
537 if ((buf == NULL) || (buf->error != 0)) {
538 #ifdef DEBUG_BUFFER
539 xmlGenericError(xmlGenericErrorContext,
540 "xmlBufDump: buf == NULL or in error\n");
541 #endif
542 return(0);
544 if (buf->content == NULL) {
545 #ifdef DEBUG_BUFFER
546 xmlGenericError(xmlGenericErrorContext,
547 "xmlBufDump: buf->content == NULL\n");
548 #endif
549 return(0);
551 CHECK_COMPAT(buf)
552 if (file == NULL)
553 file = stdout;
554 ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
555 return(ret);
559 * xmlBufContent:
560 * @buf: the buffer
562 * Function to extract the content of a buffer
564 * Returns the internal content
567 xmlChar *
568 xmlBufContent(const xmlBuf *buf)
570 if ((!buf) || (buf->error))
571 return NULL;
573 return(buf->content);
577 * xmlBufEnd:
578 * @buf: the buffer
580 * Function to extract the end of the content of a buffer
582 * Returns the end of the internal content or NULL in case of error
585 xmlChar *
586 xmlBufEnd(xmlBufPtr buf)
588 if ((!buf) || (buf->error))
589 return NULL;
590 CHECK_COMPAT(buf)
592 return(&buf->content[buf->use]);
596 * xmlBufAddLen:
597 * @buf: the buffer
598 * @len: the size which were added at the end
600 * Sometime data may be added at the end of the buffer without
601 * using the xmlBuf APIs that is used to expand the used space
602 * and set the zero terminating at the end of the buffer
604 * Returns -1 in case of error and 0 otherwise
607 xmlBufAddLen(xmlBufPtr buf, size_t len) {
608 if ((buf == NULL) || (buf->error))
609 return(-1);
610 CHECK_COMPAT(buf)
611 if (len > (buf->size - buf->use))
612 return(-1);
613 buf->use += len;
614 UPDATE_COMPAT(buf)
615 if (buf->size > buf->use)
616 buf->content[buf->use] = 0;
617 else
618 return(-1);
619 return(0);
623 * xmlBufErase:
624 * @buf: the buffer
625 * @len: the size to erase at the end
627 * Sometime data need to be erased at the end of the buffer
629 * Returns -1 in case of error and 0 otherwise
632 xmlBufErase(xmlBufPtr buf, size_t len) {
633 if ((buf == NULL) || (buf->error))
634 return(-1);
635 CHECK_COMPAT(buf)
636 if (len > buf->use)
637 return(-1);
638 buf->use -= len;
639 buf->content[buf->use] = 0;
640 UPDATE_COMPAT(buf)
641 return(0);
645 * xmlBufLength:
646 * @buf: the buffer
648 * Function to get the length of a buffer
650 * Returns the length of data in the internal content
653 size_t
654 xmlBufLength(const xmlBufPtr buf)
656 if ((!buf) || (buf->error))
657 return 0;
658 CHECK_COMPAT(buf)
660 return(buf->use);
664 * xmlBufUse:
665 * @buf: the buffer
667 * Function to get the length of a buffer
669 * Returns the length of data in the internal content
672 size_t
673 xmlBufUse(const xmlBufPtr buf)
675 if ((!buf) || (buf->error))
676 return 0;
677 CHECK_COMPAT(buf)
679 return(buf->use);
683 * xmlBufAvail:
684 * @buf: the buffer
686 * Function to find how much free space is allocated but not
687 * used in the buffer. It does not account for the terminating zero
688 * usually needed
690 * Returns the amount or 0 if none or an error occured
693 size_t
694 xmlBufAvail(const xmlBufPtr buf)
696 if ((!buf) || (buf->error))
697 return 0;
698 CHECK_COMPAT(buf)
700 return(buf->size - buf->use);
704 * xmlBufIsEmpty:
705 * @buf: the buffer
707 * Tell if a buffer is empty
709 * Returns 0 if no, 1 if yes and -1 in case of error
712 xmlBufIsEmpty(const xmlBufPtr buf)
714 if ((!buf) || (buf->error))
715 return(-1);
716 CHECK_COMPAT(buf)
718 return(buf->use == 0);
722 * xmlBufResize:
723 * @buf: the buffer to resize
724 * @size: the desired size
726 * Resize a buffer to accommodate minimum size of @size.
728 * Returns 0 in case of problems, 1 otherwise
731 xmlBufResize(xmlBufPtr buf, size_t size)
733 unsigned int newSize;
734 xmlChar* rebuf = NULL;
735 size_t start_buf;
737 if ((buf == NULL) || (buf->error))
738 return(0);
739 CHECK_COMPAT(buf)
741 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
743 /* Don't resize if we don't have to */
744 if (size < buf->size)
745 return 1;
747 /* figure out new size */
748 switch (buf->alloc){
749 case XML_BUFFER_ALLOC_IO:
750 case XML_BUFFER_ALLOC_DOUBLEIT:
751 /*take care of empty case*/
752 newSize = (buf->size ? buf->size*2 : size + 10);
753 while (size > newSize) {
754 if (newSize > UINT_MAX / 2) {
755 xmlBufMemoryError(buf, "growing buffer");
756 return 0;
758 newSize *= 2;
760 break;
761 case XML_BUFFER_ALLOC_EXACT:
762 newSize = size+10;
763 break;
764 case XML_BUFFER_ALLOC_HYBRID:
765 if (buf->use < BASE_BUFFER_SIZE)
766 newSize = size;
767 else {
768 newSize = buf->size * 2;
769 while (size > newSize) {
770 if (newSize > UINT_MAX / 2) {
771 xmlBufMemoryError(buf, "growing buffer");
772 return 0;
774 newSize *= 2;
777 break;
779 default:
780 newSize = size+10;
781 break;
784 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
785 start_buf = buf->content - buf->contentIO;
787 if (start_buf > newSize) {
788 /* move data back to start */
789 memmove(buf->contentIO, buf->content, buf->use);
790 buf->content = buf->contentIO;
791 buf->content[buf->use] = 0;
792 buf->size += start_buf;
793 } else {
794 rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
795 if (rebuf == NULL) {
796 xmlBufMemoryError(buf, "growing buffer");
797 return 0;
799 buf->contentIO = rebuf;
800 buf->content = rebuf + start_buf;
802 } else {
803 if (buf->content == NULL) {
804 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
805 } else if (buf->size - buf->use < 100) {
806 rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
807 } else {
809 * if we are reallocating a buffer far from being full, it's
810 * better to make a new allocation and copy only the used range
811 * and free the old one.
813 rebuf = (xmlChar *) xmlMallocAtomic(newSize);
814 if (rebuf != NULL) {
815 memcpy(rebuf, buf->content, buf->use);
816 xmlFree(buf->content);
817 rebuf[buf->use] = 0;
820 if (rebuf == NULL) {
821 xmlBufMemoryError(buf, "growing buffer");
822 return 0;
824 buf->content = rebuf;
826 buf->size = newSize;
827 UPDATE_COMPAT(buf)
829 return 1;
833 * xmlBufAdd:
834 * @buf: the buffer to dump
835 * @str: the #xmlChar string
836 * @len: the number of #xmlChar to add
838 * Add a string range to an XML buffer. if len == -1, the length of
839 * str is recomputed.
841 * Returns 0 successful, a positive error code number otherwise
842 * and -1 in case of internal or API error.
845 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
846 unsigned int needSize;
848 if ((str == NULL) || (buf == NULL) || (buf->error))
849 return -1;
850 CHECK_COMPAT(buf)
852 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
853 if (len < -1) {
854 #ifdef DEBUG_BUFFER
855 xmlGenericError(xmlGenericErrorContext,
856 "xmlBufAdd: len < 0\n");
857 #endif
858 return -1;
860 if (len == 0) return 0;
862 if (len < 0)
863 len = xmlStrlen(str);
865 if (len < 0) return -1;
866 if (len == 0) return 0;
868 needSize = buf->use + len + 2;
869 if (needSize > buf->size){
870 if (!xmlBufResize(buf, needSize)){
871 xmlBufMemoryError(buf, "growing buffer");
872 return XML_ERR_NO_MEMORY;
876 memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
877 buf->use += len;
878 buf->content[buf->use] = 0;
879 UPDATE_COMPAT(buf)
880 return 0;
884 * xmlBufAddHead:
885 * @buf: the buffer
886 * @str: the #xmlChar string
887 * @len: the number of #xmlChar to add
889 * Add a string range to the beginning of an XML buffer.
890 * if len == -1, the length of @str is recomputed.
892 * Returns 0 successful, a positive error code number otherwise
893 * and -1 in case of internal or API error.
896 xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
897 unsigned int needSize;
899 if ((buf == NULL) || (buf->error))
900 return(-1);
901 CHECK_COMPAT(buf)
902 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
903 if (str == NULL) {
904 #ifdef DEBUG_BUFFER
905 xmlGenericError(xmlGenericErrorContext,
906 "xmlBufAddHead: str == NULL\n");
907 #endif
908 return -1;
910 if (len < -1) {
911 #ifdef DEBUG_BUFFER
912 xmlGenericError(xmlGenericErrorContext,
913 "xmlBufAddHead: len < 0\n");
914 #endif
915 return -1;
917 if (len == 0) return 0;
919 if (len < 0)
920 len = xmlStrlen(str);
922 if (len <= 0) return -1;
924 if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
925 size_t start_buf = buf->content - buf->contentIO;
927 if (start_buf > (unsigned int) len) {
929 * We can add it in the space previously shrinked
931 buf->content -= len;
932 memmove(&buf->content[0], str, len);
933 buf->use += len;
934 buf->size += len;
935 UPDATE_COMPAT(buf)
936 return(0);
939 needSize = buf->use + len + 2;
940 if (needSize > buf->size){
941 if (!xmlBufResize(buf, needSize)){
942 xmlBufMemoryError(buf, "growing buffer");
943 return XML_ERR_NO_MEMORY;
947 memmove(&buf->content[len], &buf->content[0], buf->use);
948 memmove(&buf->content[0], str, len);
949 buf->use += len;
950 buf->content[buf->use] = 0;
951 UPDATE_COMPAT(buf)
952 return 0;
956 * xmlBufCat:
957 * @buf: the buffer to add to
958 * @str: the #xmlChar string
960 * Append a zero terminated string to an XML buffer.
962 * Returns 0 successful, a positive error code number otherwise
963 * and -1 in case of internal or API error.
966 xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
967 if ((buf == NULL) || (buf->error))
968 return(-1);
969 CHECK_COMPAT(buf)
970 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
971 if (str == NULL) return -1;
972 return xmlBufAdd(buf, str, -1);
976 * xmlBufCCat:
977 * @buf: the buffer to dump
978 * @str: the C char string
980 * Append a zero terminated C string to an XML buffer.
982 * Returns 0 successful, a positive error code number otherwise
983 * and -1 in case of internal or API error.
986 xmlBufCCat(xmlBufPtr buf, const char *str) {
987 const char *cur;
989 if ((buf == NULL) || (buf->error))
990 return(-1);
991 CHECK_COMPAT(buf)
992 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
993 if (str == NULL) {
994 #ifdef DEBUG_BUFFER
995 xmlGenericError(xmlGenericErrorContext,
996 "xmlBufCCat: str == NULL\n");
997 #endif
998 return -1;
1000 for (cur = str;*cur != 0;cur++) {
1001 if (buf->use + 10 >= buf->size) {
1002 if (!xmlBufResize(buf, buf->use+10)){
1003 xmlBufMemoryError(buf, "growing buffer");
1004 return XML_ERR_NO_MEMORY;
1007 buf->content[buf->use++] = *cur;
1009 buf->content[buf->use] = 0;
1010 UPDATE_COMPAT(buf)
1011 return 0;
1015 * xmlBufWriteCHAR:
1016 * @buf: the XML buffer
1017 * @string: the string to add
1019 * routine which manages and grows an output buffer. This one adds
1020 * xmlChars at the end of the buffer.
1022 * Returns 0 if successful, a positive error code number otherwise
1023 * and -1 in case of internal or API error.
1026 xmlBufWriteCHAR(xmlBufPtr buf, const xmlChar *string) {
1027 if ((buf == NULL) || (buf->error))
1028 return(-1);
1029 CHECK_COMPAT(buf)
1030 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1031 return(-1);
1032 return(xmlBufCat(buf, string));
1036 * xmlBufWriteChar:
1037 * @buf: the XML buffer output
1038 * @string: the string to add
1040 * routine which manage and grows an output buffer. This one add
1041 * C chars at the end of the array.
1043 * Returns 0 if successful, a positive error code number otherwise
1044 * and -1 in case of internal or API error.
1047 xmlBufWriteChar(xmlBufPtr buf, const char *string) {
1048 if ((buf == NULL) || (buf->error))
1049 return(-1);
1050 CHECK_COMPAT(buf)
1051 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1052 return(-1);
1053 return(xmlBufCCat(buf, string));
1058 * xmlBufWriteQuotedString:
1059 * @buf: the XML buffer output
1060 * @string: the string to add
1062 * routine which manage and grows an output buffer. This one writes
1063 * a quoted or double quoted #xmlChar string, checking first if it holds
1064 * quote or double-quotes internally
1066 * Returns 0 if successful, a positive error code number otherwise
1067 * and -1 in case of internal or API error.
1070 xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
1071 const xmlChar *cur, *base;
1072 if ((buf == NULL) || (buf->error))
1073 return(-1);
1074 CHECK_COMPAT(buf)
1075 if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1076 return(-1);
1077 if (xmlStrchr(string, '\"')) {
1078 if (xmlStrchr(string, '\'')) {
1079 #ifdef DEBUG_BUFFER
1080 xmlGenericError(xmlGenericErrorContext,
1081 "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
1082 #endif
1083 xmlBufCCat(buf, "\"");
1084 base = cur = string;
1085 while(*cur != 0){
1086 if(*cur == '"'){
1087 if (base != cur)
1088 xmlBufAdd(buf, base, cur - base);
1089 xmlBufAdd(buf, BAD_CAST "&quot;", 6);
1090 cur++;
1091 base = cur;
1093 else {
1094 cur++;
1097 if (base != cur)
1098 xmlBufAdd(buf, base, cur - base);
1099 xmlBufCCat(buf, "\"");
1101 else{
1102 xmlBufCCat(buf, "\'");
1103 xmlBufCat(buf, string);
1104 xmlBufCCat(buf, "\'");
1106 } else {
1107 xmlBufCCat(buf, "\"");
1108 xmlBufCat(buf, string);
1109 xmlBufCCat(buf, "\"");
1111 return(0);
1115 * xmlBufFromBuffer:
1116 * @buffer: incoming old buffer to convert to a new one
1118 * Helper routine to switch from the old buffer structures in use
1119 * in various APIs. It creates a wrapper xmlBufPtr which will be
1120 * used for internal processing until the xmlBufBackToBuffer() is
1121 * issued.
1123 * Returns a new xmlBufPtr unless the call failed and NULL is returned
1125 xmlBufPtr
1126 xmlBufFromBuffer(xmlBufferPtr buffer) {
1127 xmlBufPtr ret;
1129 if (buffer == NULL)
1130 return(NULL);
1132 ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
1133 if (ret == NULL) {
1134 xmlBufMemoryError(NULL, "creating buffer");
1135 return(NULL);
1137 ret->use = buffer->use;
1138 ret->size = buffer->size;
1139 ret->compat_use = buffer->use;
1140 ret->compat_size = buffer->size;
1141 ret->error = 0;
1142 ret->buffer = buffer;
1143 ret->alloc = buffer->alloc;
1144 ret->content = buffer->content;
1145 ret->contentIO = buffer->contentIO;
1147 return(ret);
1151 * xmlBufBackToBuffer:
1152 * @buf: new buffer wrapping the old one
1154 * Function to be called once internal processing had been done to
1155 * update back the buffer provided by the user. This can lead to
1156 * a failure in case the size accumulated in the xmlBuf is larger
1157 * than what an xmlBuffer can support on 64 bits (INT_MAX)
1158 * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
1160 * Returns the old xmlBufferPtr unless the call failed and NULL is returned
1162 xmlBufferPtr
1163 xmlBufBackToBuffer(xmlBufPtr buf) {
1164 xmlBufferPtr ret;
1166 if ((buf == NULL) || (buf->error))
1167 return(NULL);
1168 CHECK_COMPAT(buf)
1169 if (buf->buffer == NULL) {
1170 xmlBufFree(buf);
1171 return(NULL);
1174 ret = buf->buffer;
1176 * What to do in case of error in the buffer ???
1178 if (buf->use > INT_MAX) {
1180 * Worse case, we really allocated and used more than the
1181 * maximum allowed memory for an xmlBuffer on this architecture.
1182 * Keep the buffer but provide a truncated size value.
1184 xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
1185 ret->use = INT_MAX;
1186 ret->size = INT_MAX;
1187 } else if (buf->size > INT_MAX) {
1189 * milder case, we allocated more than the maximum allowed memory
1190 * for an xmlBuffer on this architecture, but used less than the
1191 * limit.
1192 * Keep the buffer but provide a truncated size value.
1194 xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
1195 ret->size = INT_MAX;
1197 ret->use = (int) buf->use;
1198 ret->size = (int) buf->size;
1199 ret->alloc = buf->alloc;
1200 ret->content = buf->content;
1201 ret->contentIO = buf->contentIO;
1202 xmlFree(buf);
1203 return(ret);
1207 * xmlBufMergeBuffer:
1208 * @buf: an xmlBufPtr
1209 * @buffer: the buffer to consume into @buf
1211 * The content of @buffer is appended to @buf and @buffer is freed
1213 * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
1216 xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
1217 int ret = 0;
1219 if ((buf == NULL) || (buf->error)) {
1220 xmlBufferFree(buffer);
1221 return(-1);
1223 CHECK_COMPAT(buf)
1224 if ((buffer != NULL) && (buffer->content != NULL) &&
1225 (buffer->use > 0)) {
1226 ret = xmlBufAdd(buf, buffer->content, buffer->use);
1228 xmlBufferFree(buffer);
1229 return(ret);
1233 * xmlBufResetInput:
1234 * @buf: an xmlBufPtr
1235 * @input: an xmlParserInputPtr
1237 * Update the input to use the current set of pointers from the buffer.
1239 * Returns -1 in case of error, 0 otherwise
1242 xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
1243 if ((input == NULL) || (buf == NULL) || (buf->error))
1244 return(-1);
1245 CHECK_COMPAT(buf)
1246 input->base = input->cur = buf->content;
1247 input->end = &buf->content[buf->use];
1248 return(0);
1252 * xmlBufGetInputBase:
1253 * @buf: an xmlBufPtr
1254 * @input: an xmlParserInputPtr
1256 * Get the base of the @input relative to the beginning of the buffer
1258 * Returns the size_t corresponding to the displacement
1260 size_t
1261 xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
1262 size_t base;
1264 if ((input == NULL) || (buf == NULL) || (buf->error))
1265 return(-1);
1266 CHECK_COMPAT(buf)
1267 base = input->base - buf->content;
1269 * We could do some pointer arythmetic checks but that's probably
1270 * sufficient.
1272 if (base > buf->size) {
1273 xmlBufOverflowError(buf, "Input reference outside of the buffer");
1274 base = 0;
1276 return(base);
1280 * xmlBufSetInputBaseCur:
1281 * @buf: an xmlBufPtr
1282 * @input: an xmlParserInputPtr
1283 * @base: the base value relative to the beginning of the buffer
1284 * @cur: the cur value relative to the beginning of the buffer
1286 * Update the input to use the base and cur relative to the buffer
1287 * after a possible reallocation of its content
1289 * Returns -1 in case of error, 0 otherwise
1292 xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
1293 size_t base, size_t cur) {
1294 if ((input == NULL) || (buf == NULL) || (buf->error))
1295 return(-1);
1296 CHECK_COMPAT(buf)
1297 input->base = &buf->content[base];
1298 input->cur = input->base + cur;
1299 input->end = &buf->content[buf->use];
1300 return(0);
1303 #define bottom_buf
1304 #include "elfgcchack.h"