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