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.
18 #include <string.h> /* for memset() only ! */
27 #include <libxml/tree.h>
28 #include <libxml/globals.h>
29 #include <libxml/tree.h>
32 #define WITH_BUFFER_COMPAT
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.
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 */
85 * @extra: extra informations
87 * Handle an out of memory condition
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
;
99 * xmlBufOverflowError:
100 * @extra: extra informations
102 * Handle a buffer overflow error
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
;
117 * routine to create an XML buffer.
118 * returns the new structure.
124 ret
= (xmlBufPtr
) xmlMalloc(sizeof(xmlBuf
));
126 xmlBufMemoryError(NULL
, "creating buffer");
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");
143 ret
->contentIO
= NULL
;
149 * @size: initial size of buffer
151 * routine to create an XML buffer.
152 * returns the new structure.
155 xmlBufCreateSize(size_t size
) {
158 ret
= (xmlBufPtr
) xmlMalloc(sizeof(xmlBuf
));
160 xmlBufMemoryError(NULL
, "creating buffer");
167 ret
->alloc
= xmlBufferAllocScheme
;
168 ret
->size
= (size
? size
+2 : 0); /* +1 for ending null */
169 ret
->compat_size
= (int) ret
->size
;
171 ret
->content
= (xmlChar
*) xmlMallocAtomic(ret
->size
* sizeof(xmlChar
));
172 if (ret
->content
== NULL
) {
173 xmlBufMemoryError(ret
, "creating buffer");
180 ret
->contentIO
= NULL
;
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.
195 xmlBufDetach(xmlBufPtr buf
) {
200 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
)
202 if (buf
->buffer
!= NULL
)
212 buf
->compat_size
= 0;
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.
230 xmlBufCreateStatic(void *mem
, size_t size
) {
233 if ((mem
== NULL
) || (size
== 0))
236 ret
= (xmlBufPtr
) xmlMalloc(sizeof(xmlBuf
));
238 xmlBufMemoryError(NULL
, "creating buffer");
241 if (size
< INT_MAX
) {
242 ret
->compat_use
= size
;
243 ret
->compat_size
= size
;
245 ret
->compat_use
= INT_MAX
;
246 ret
->compat_size
= INT_MAX
;
250 ret
->alloc
= XML_BUFFER_ALLOC_IMMUTABLE
;
251 ret
->content
= (xmlChar
*) mem
;
258 * xmlBufGetAllocationScheme:
261 * Get the buffer allocation scheme
263 * Returns the scheme or -1 in case of error
266 xmlBufGetAllocationScheme(xmlBufPtr buf
) {
269 xmlGenericError(xmlGenericErrorContext
,
270 "xmlBufGetAllocationScheme: buf == NULL\n");
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)) {
291 xmlGenericError(xmlGenericErrorContext
,
292 "xmlBufSetAllocationScheme: buf == NULL or in error\n");
296 if ((buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
) ||
297 (buf
->alloc
== XML_BUFFER_ALLOC_IO
))
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
)) {
305 buf
->buffer
->alloc
= scheme
;
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
;
321 * @buf: the buffer to free
323 * Frees an XML buffer. It frees both the content and the structure which
327 xmlBufFree(xmlBufPtr buf
) {
330 xmlGenericError(xmlGenericErrorContext
,
331 "xmlBufFree: buf == NULL\n");
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
);
353 xmlBufEmpty(xmlBufPtr buf
) {
354 if ((buf
== NULL
) || (buf
->error
!= 0)) return;
355 if (buf
->content
== NULL
) return;
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
;
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
386 xmlBufShrink(xmlBufPtr buf
, size_t len
) {
387 if ((buf
== NULL
) || (buf
->error
!= 0)) return(0);
389 if (len
== 0) return(0);
390 if (len
> buf
->use
) return(0);
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
403 * sometimes though it maybe be better to really shrink
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
;
416 memmove(buf
->content
, &buf
->content
[len
], buf
->use
);
417 buf
->content
[buf
->use
] = 0;
424 * xmlBufGrowInternal:
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
435 xmlBufGrowInternal(xmlBufPtr buf
, size_t len
) {
439 if ((buf
== NULL
) || (buf
->error
!= 0)) return(0);
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
453 if (buf
->size
> (size_t) len
)
454 size
= buf
->size
* 2;
456 size
= buf
->use
+ len
+ 100;
458 size
= buf
->use
+ len
+ 100;
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");
469 buf
->contentIO
= newbuf
;
470 buf
->content
= newbuf
+ start_buf
;
472 newbuf
= (xmlChar
*) xmlRealloc(buf
->content
, size
);
473 if (newbuf
== NULL
) {
474 xmlBufMemoryError(buf
, "growing buffer");
477 buf
->content
= newbuf
;
481 return(buf
->size
- buf
->use
);
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
) {
498 if ((buf
== NULL
) || (len
< 0)) return(-1);
501 ret
= xmlBufGrowInternal(buf
, len
);
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
);
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
534 xmlBufDump(FILE *file
, xmlBufPtr buf
) {
537 if ((buf
== NULL
) || (buf
->error
!= 0)) {
539 xmlGenericError(xmlGenericErrorContext
,
540 "xmlBufDump: buf == NULL or in error\n");
544 if (buf
->content
== NULL
) {
546 xmlGenericError(xmlGenericErrorContext
,
547 "xmlBufDump: buf->content == NULL\n");
554 ret
= fwrite(buf
->content
, sizeof(xmlChar
), buf
->use
, file
);
562 * Function to extract the content of a buffer
564 * Returns the internal content
568 xmlBufContent(const xmlBuf
*buf
)
570 if ((!buf
) || (buf
->error
))
573 return(buf
->content
);
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
586 xmlBufEnd(xmlBufPtr buf
)
588 if ((!buf
) || (buf
->error
))
592 return(&buf
->content
[buf
->use
]);
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
))
611 if (len
> (buf
->size
- buf
->use
))
615 if (buf
->size
> buf
->use
)
616 buf
->content
[buf
->use
] = 0;
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
))
639 buf
->content
[buf
->use
] = 0;
648 * Function to get the length of a buffer
650 * Returns the length of data in the internal content
654 xmlBufLength(const xmlBufPtr buf
)
656 if ((!buf
) || (buf
->error
))
667 * Function to get the length of a buffer
669 * Returns the length of data in the internal content
673 xmlBufUse(const xmlBufPtr buf
)
675 if ((!buf
) || (buf
->error
))
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
690 * Returns the amount or 0 if none or an error occured
694 xmlBufAvail(const xmlBufPtr buf
)
696 if ((!buf
) || (buf
->error
))
700 return(buf
->size
- buf
->use
);
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
))
718 return(buf
->use
== 0);
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
;
737 if ((buf
== NULL
) || (buf
->error
))
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
)
747 /* figure out new size */
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");
761 case XML_BUFFER_ALLOC_EXACT
:
764 case XML_BUFFER_ALLOC_HYBRID
:
765 if (buf
->use
< BASE_BUFFER_SIZE
)
768 newSize
= buf
->size
* 2;
769 while (size
> newSize
) {
770 if (newSize
> UINT_MAX
/ 2) {
771 xmlBufMemoryError(buf
, "growing buffer");
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
;
794 rebuf
= (xmlChar
*) xmlRealloc(buf
->contentIO
, start_buf
+ newSize
);
796 xmlBufMemoryError(buf
, "growing buffer");
799 buf
->contentIO
= rebuf
;
800 buf
->content
= rebuf
+ start_buf
;
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
);
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
);
815 memcpy(rebuf
, buf
->content
, buf
->use
);
816 xmlFree(buf
->content
);
821 xmlBufMemoryError(buf
, "growing buffer");
824 buf
->content
= rebuf
;
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
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
))
852 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
) return -1;
855 xmlGenericError(xmlGenericErrorContext
,
856 "xmlBufAdd: len < 0\n");
860 if (len
== 0) return 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
));
878 buf
->content
[buf
->use
] = 0;
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
))
902 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
) return -1;
905 xmlGenericError(xmlGenericErrorContext
,
906 "xmlBufAddHead: str == NULL\n");
912 xmlGenericError(xmlGenericErrorContext
,
913 "xmlBufAddHead: len < 0\n");
917 if (len
== 0) return 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
932 memmove(&buf
->content
[0], str
, len
);
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
);
950 buf
->content
[buf
->use
] = 0;
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
))
970 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
) return -1;
971 if (str
== NULL
) return -1;
972 return xmlBufAdd(buf
, str
, -1);
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
) {
989 if ((buf
== NULL
) || (buf
->error
))
992 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
) return -1;
995 xmlGenericError(xmlGenericErrorContext
,
996 "xmlBufCCat: str == NULL\n");
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;
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
))
1030 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
)
1032 return(xmlBufCat(buf
, string
));
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
))
1051 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
)
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
))
1075 if (buf
->alloc
== XML_BUFFER_ALLOC_IMMUTABLE
)
1077 if (xmlStrchr(string
, '\"')) {
1078 if (xmlStrchr(string
, '\'')) {
1080 xmlGenericError(xmlGenericErrorContext
,
1081 "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
1083 xmlBufCCat(buf
, "\"");
1084 base
= cur
= string
;
1088 xmlBufAdd(buf
, base
, cur
- base
);
1089 xmlBufAdd(buf
, BAD_CAST
""", 6);
1098 xmlBufAdd(buf
, base
, cur
- base
);
1099 xmlBufCCat(buf
, "\"");
1102 xmlBufCCat(buf
, "\'");
1103 xmlBufCat(buf
, string
);
1104 xmlBufCCat(buf
, "\'");
1107 xmlBufCCat(buf
, "\"");
1108 xmlBufCat(buf
, string
);
1109 xmlBufCCat(buf
, "\"");
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
1123 * Returns a new xmlBufPtr unless the call failed and NULL is returned
1126 xmlBufFromBuffer(xmlBufferPtr buffer
) {
1132 ret
= (xmlBufPtr
) xmlMalloc(sizeof(xmlBuf
));
1134 xmlBufMemoryError(NULL
, "creating buffer");
1137 ret
->use
= buffer
->use
;
1138 ret
->size
= buffer
->size
;
1139 ret
->compat_use
= buffer
->use
;
1140 ret
->compat_size
= buffer
->size
;
1142 ret
->buffer
= buffer
;
1143 ret
->alloc
= buffer
->alloc
;
1144 ret
->content
= buffer
->content
;
1145 ret
->contentIO
= buffer
->contentIO
;
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
1163 xmlBufBackToBuffer(xmlBufPtr buf
) {
1166 if ((buf
== NULL
) || (buf
->error
))
1169 if (buf
->buffer
== NULL
) {
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");
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
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
;
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
) {
1219 if ((buf
== NULL
) || (buf
->error
)) {
1220 xmlBufferFree(buffer
);
1224 if ((buffer
!= NULL
) && (buffer
->content
!= NULL
) &&
1225 (buffer
->use
> 0)) {
1226 ret
= xmlBufAdd(buf
, buffer
->content
, buffer
->use
);
1228 xmlBufferFree(buffer
);
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
))
1246 input
->base
= input
->cur
= buf
->content
;
1247 input
->end
= &buf
->content
[buf
->use
];
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
1261 xmlBufGetInputBase(xmlBufPtr buf
, xmlParserInputPtr input
) {
1264 if ((input
== NULL
) || (buf
== NULL
) || (buf
->error
))
1267 base
= input
->base
- buf
->content
;
1269 * We could do some pointer arythmetic checks but that's probably
1272 if (base
> buf
->size
) {
1273 xmlBufOverflowError(buf
, "Input reference outside of the buffer");
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
))
1297 input
->base
= &buf
->content
[base
];
1298 input
->cur
= input
->base
+ cur
;
1299 input
->end
= &buf
->content
[buf
->use
];
1304 #include "elfgcchack.h"