6efc7b677c33d3b895555c43a0988d18c97448a2
[platform/upstream/libxml2.git] / buf.c
1 /*
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 #define WITH_BUFFER_COMPAT
33
34 /**
35  * xmlBuf:
36  *
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.
40  */
41
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 */
52 };
53
54 #ifdef WITH_BUFFER_COMPAT
55 /*
56  * Macro for compatibility with xmlBuffer to be used after an xmlBuf
57  * is updated. This makes sure the compat fields are updated too.
58  */
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;
64
65 /*
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 .
69  */
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;
77
78 #else /* ! WITH_BUFFER_COMPAT */
79 #define UPDATE_COMPAT(buf)
80 #define CHECK_COMPAT(buf)
81 #endif /* WITH_BUFFER_COMPAT */
82
83 /**
84  * xmlBufMemoryError:
85  * @extra:  extra informations
86  *
87  * Handle an out of memory condition
88  * To be improved...
89  */
90 static void
91 xmlBufMemoryError(xmlBufPtr buf, const char *extra)
92 {
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;
96 }
97
98 /**
99  * xmlBufOverflowError:
100  * @extra:  extra informations
101  *
102  * Handle a buffer overflow error
103  * To be improved...
104  */
105 static void
106 xmlBufOverflowError(xmlBufPtr buf, const char *extra)
107 {
108     __xmlSimpleError(XML_FROM_BUFFER, XML_BUF_OVERFLOW, NULL, NULL, extra);
109     if ((buf) && (buf->error == 0))
110         buf->error = XML_BUF_OVERFLOW;
111 }
112
113
114 /**
115  * xmlBufCreate:
116  *
117  * routine to create an XML buffer.
118  * returns the new structure.
119  */
120 xmlBufPtr
121 xmlBufCreate(void) {
122     xmlBufPtr ret;
123
124     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
125     if (ret == NULL) {
126         xmlBufMemoryError(NULL, "creating buffer");
127         return(NULL);
128     }
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);
141     }
142     ret->content[0] = 0;
143     ret->contentIO = NULL;
144     return(ret);
145 }
146
147 /**
148  * xmlBufCreateSize:
149  * @size: initial size of buffer
150  *
151  * routine to create an XML buffer.
152  * returns the new structure.
153  */
154 xmlBufPtr
155 xmlBufCreateSize(size_t size) {
156     xmlBufPtr ret;
157
158     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
159     if (ret == NULL) {
160         xmlBufMemoryError(NULL, "creating buffer");
161         return(NULL);
162     }
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);
176         }
177         ret->content[0] = 0;
178     } else
179         ret->content = NULL;
180     ret->contentIO = NULL;
181     return(ret);
182 }
183
184 /**
185  * xmlBufDetach:
186  * @buf:  the buffer
187  *
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.
191  *
192  * Returns the previous string contained by the buffer.
193  */
194 xmlChar *
195 xmlBufDetach(xmlBufPtr buf) {
196     xmlChar *ret;
197
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);
206
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;
213
214     return ret;
215 }
216
217
218 /**
219  * xmlBufCreateStatic:
220  * @mem: the memory area
221  * @size:  the size in byte
222  *
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.
226  *
227  * returns the new structure.
228  */
229 xmlBufPtr
230 xmlBufCreateStatic(void *mem, size_t size) {
231     xmlBufPtr ret;
232
233     if ((mem == NULL) || (size == 0))
234         return(NULL);
235
236     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
237     if (ret == NULL) {
238         xmlBufMemoryError(NULL, "creating buffer");
239         return(NULL);
240     }
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;
247     }
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);
255 }
256
257 /**
258  * xmlBufGetAllocationScheme:
259  * @buf:  the buffer
260  *
261  * Get the buffer allocation scheme
262  *
263  * Returns the scheme or -1 in case of error
264  */
265 int
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);
273     }
274     return(buf->alloc);
275 }
276
277 /**
278  * xmlBufSetAllocationScheme:
279  * @buf:  the buffer to tune
280  * @scheme:  allocation scheme to use
281  *
282  * Sets the allocation scheme for this buffer
283  *
284  * returns 0 in case of success and -1 in case of failure
285  */
286 int
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);
295     }
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);
307     }
308     /*
309      * Switching a buffer ALLOC_IO has the side effect of initializing
310      * the contentIO field with the current content
311      */
312     if (scheme == XML_BUFFER_ALLOC_IO) {
313         buf->alloc = XML_BUFFER_ALLOC_IO;
314         buf->contentIO = buf->content;
315     }
316     return(-1);
317 }
318
319 /**
320  * xmlBufFree:
321  * @buf:  the buffer to free
322  *
323  * Frees an XML buffer. It frees both the content and the structure which
324  * encapsulate it.
325  */
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;
334     }
335
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);
342     }
343     xmlFree(buf);
344 }
345
346 /**
347  * xmlBufEmpty:
348  * @buf:  the buffer
349  *
350  * empty a buffer.
351  */
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;
363
364         buf->size += start_buf;
365         buf->content = buf->contentIO;
366         buf->content[0] = 0;
367     } else {
368         buf->content[0] = 0;
369     }
370     UPDATE_COMPAT(buf)
371 }
372
373 /**
374  * xmlBufShrink:
375  * @buf:  the buffer to dump
376  * @len:  the number of xmlChar to remove
377  *
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.
382  *
383  * Returns the number of byte removed or 0 in case of failure
384  */
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);
391
392     buf->use -= len;
393     if ((buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) ||
394         ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL))) {
395         /*
396          * we just move the content pointer, but also make sure
397          * the perceived buffer size has shrinked accordingly
398          */
399         buf->content += len;
400         buf->size -= len;
401
402         /*
403          * sometimes though it maybe be better to really shrink
404          * on IO buffers
405          */
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;
413             }
414         }
415     } else {
416         memmove(buf->content, &buf->content[len], buf->use);
417         buf->content[buf->use] = 0;
418     }
419     UPDATE_COMPAT(buf)
420     return(len);
421 }
422
423 /**
424  * xmlBufGrowInternal:
425  * @buf:  the buffer
426  * @len:  the minimum free size to allocate
427  *
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
431  *
432  * Returns 0 in case of error or the length made available otherwise
433  */
434 static size_t
435 xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
436     size_t size;
437     xmlChar *newbuf;
438
439     if ((buf == NULL) || (buf->error != 0)) return(0);
440     CHECK_COMPAT(buf)
441
442     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
443     if (buf->use + len < buf->size)
444         return(buf->size - buf->use);
445
446     /*
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
451      */
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
460
461     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
462         size_t start_buf = buf->content - buf->contentIO;
463
464         newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
465         if (newbuf == NULL) {
466             xmlBufMemoryError(buf, "growing buffer");
467             return(0);
468         }
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);
476         }
477         buf->content = newbuf;
478     }
479     buf->size = size;
480     UPDATE_COMPAT(buf)
481     return(buf->size - buf->use);
482 }
483
484 /**
485  * xmlBufGrow:
486  * @buf:  the buffer
487  * @len:  the minimum free size to allocate
488  *
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
491  *
492  * Returns -1 in case of error or the length made available otherwise
493  */
494 int
495 xmlBufGrow(xmlBufPtr buf, int len) {
496     size_t ret;
497
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);
505 }
506
507 /**
508  * xmlBufInflate:
509  * @buf:  the buffer
510  * @len:  the minimum extra free size to allocate
511  *
512  * Grow the available space of an XML buffer, adding at least @len bytes
513  *
514  * Returns 0 if successful or -1 in case of error
515  */
516 int
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);
523 }
524
525 /**
526  * xmlBufDump:
527  * @file:  the file output
528  * @buf:  the buffer to dump
529  *
530  * Dumps an XML buffer to  a FILE *.
531  * Returns the number of #xmlChar written
532  */
533 size_t
534 xmlBufDump(FILE *file, xmlBufPtr buf) {
535     size_t ret;
536
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);
543     }
544     if (buf->content == NULL) {
545 #ifdef DEBUG_BUFFER
546         xmlGenericError(xmlGenericErrorContext,
547                 "xmlBufDump: buf->content == NULL\n");
548 #endif
549         return(0);
550     }
551     CHECK_COMPAT(buf)
552     if (file == NULL)
553         file = stdout;
554     ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
555     return(ret);
556 }
557
558 /**
559  * xmlBufContent:
560  * @buf:  the buffer
561  *
562  * Function to extract the content of a buffer
563  *
564  * Returns the internal content
565  */
566
567 xmlChar *
568 xmlBufContent(const xmlBuf *buf)
569 {
570     if ((!buf) || (buf->error))
571         return NULL;
572
573     return(buf->content);
574 }
575
576 /**
577  * xmlBufEnd:
578  * @buf:  the buffer
579  *
580  * Function to extract the end of the content of a buffer
581  *
582  * Returns the end of the internal content or NULL in case of error
583  */
584
585 xmlChar *
586 xmlBufEnd(xmlBufPtr buf)
587 {
588     if ((!buf) || (buf->error))
589         return NULL;
590     CHECK_COMPAT(buf)
591
592     return(&buf->content[buf->use]);
593 }
594
595 /**
596  * xmlBufAddLen:
597  * @buf:  the buffer
598  * @len:  the size which were added at the end
599  *
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
603  *
604  * Returns -1 in case of error and 0 otherwise
605  */
606 int
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);
620 }
621
622 /**
623  * xmlBufErase:
624  * @buf:  the buffer
625  * @len:  the size to erase at the end
626  *
627  * Sometime data need to be erased at the end of the buffer
628  *
629  * Returns -1 in case of error and 0 otherwise
630  */
631 int
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);
642 }
643
644 /**
645  * xmlBufLength:
646  * @buf:  the buffer
647  *
648  * Function to get the length of a buffer
649  *
650  * Returns the length of data in the internal content
651  */
652
653 size_t
654 xmlBufLength(const xmlBufPtr buf)
655 {
656     if ((!buf) || (buf->error))
657         return 0;
658     CHECK_COMPAT(buf)
659
660     return(buf->use);
661 }
662
663 /**
664  * xmlBufUse:
665  * @buf:  the buffer
666  *
667  * Function to get the length of a buffer
668  *
669  * Returns the length of data in the internal content
670  */
671
672 size_t
673 xmlBufUse(const xmlBufPtr buf)
674 {
675     if ((!buf) || (buf->error))
676         return 0;
677     CHECK_COMPAT(buf)
678
679     return(buf->use);
680 }
681
682 /**
683  * xmlBufAvail:
684  * @buf:  the buffer
685  *
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
689  *
690  * Returns the amount or 0 if none or an error occured
691  */
692
693 size_t
694 xmlBufAvail(const xmlBufPtr buf)
695 {
696     if ((!buf) || (buf->error))
697         return 0;
698     CHECK_COMPAT(buf)
699
700     return(buf->size - buf->use);
701 }
702
703 /**
704  * xmlBufIsEmpty:
705  * @buf:  the buffer
706  *
707  * Tell if a buffer is empty
708  *
709  * Returns 0 if no, 1 if yes and -1 in case of error
710  */
711 int
712 xmlBufIsEmpty(const xmlBufPtr buf)
713 {
714     if ((!buf) || (buf->error))
715         return(-1);
716     CHECK_COMPAT(buf)
717
718     return(buf->use == 0);
719 }
720
721 /**
722  * xmlBufResize:
723  * @buf:  the buffer to resize
724  * @size:  the desired size
725  *
726  * Resize a buffer to accommodate minimum size of @size.
727  *
728  * Returns  0 in case of problems, 1 otherwise
729  */
730 int
731 xmlBufResize(xmlBufPtr buf, size_t size)
732 {
733     unsigned int newSize;
734     xmlChar* rebuf = NULL;
735     size_t start_buf;
736
737     if ((buf == NULL) || (buf->error))
738         return(0);
739     CHECK_COMPAT(buf)
740
741     if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
742
743     /* Don't resize if we don't have to */
744     if (size < buf->size)
745         return 1;
746
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;
757                 }
758                 newSize *= 2;
759             }
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;
773                     }
774                     newSize *= 2;
775                 }
776             }
777             break;
778
779         default:
780             newSize = size+10;
781             break;
782     }
783
784     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
785         start_buf = buf->content - buf->contentIO;
786
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;
798             }
799             buf->contentIO = rebuf;
800             buf->content = rebuf + start_buf;
801         }
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 {
808             /*
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.
812              */
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;
818             }
819         }
820         if (rebuf == NULL) {
821             xmlBufMemoryError(buf, "growing buffer");
822             return 0;
823         }
824         buf->content = rebuf;
825     }
826     buf->size = newSize;
827     UPDATE_COMPAT(buf)
828
829     return 1;
830 }
831
832 /**
833  * xmlBufAdd:
834  * @buf:  the buffer to dump
835  * @str:  the #xmlChar string
836  * @len:  the number of #xmlChar to add
837  *
838  * Add a string range to an XML buffer. if len == -1, the length of
839  * str is recomputed.
840  *
841  * Returns 0 successful, a positive error code number otherwise
842  *         and -1 in case of internal or API error.
843  */
844 int
845 xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
846     unsigned int needSize;
847
848     if ((str == NULL) || (buf == NULL) || (buf->error))
849         return -1;
850     CHECK_COMPAT(buf)
851
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;
859     }
860     if (len == 0) return 0;
861
862     if (len < 0)
863         len = xmlStrlen(str);
864
865     if (len < 0) return -1;
866     if (len == 0) return 0;
867
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;
873         }
874     }
875
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;
881 }
882
883 /**
884  * xmlBufAddHead:
885  * @buf:  the buffer
886  * @str:  the #xmlChar string
887  * @len:  the number of #xmlChar to add
888  *
889  * Add a string range to the beginning of an XML buffer.
890  * if len == -1, the length of @str is recomputed.
891  *
892  * Returns 0 successful, a positive error code number otherwise
893  *         and -1 in case of internal or API error.
894  */
895 int
896 xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
897     unsigned int needSize;
898
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;
909     }
910     if (len < -1) {
911 #ifdef DEBUG_BUFFER
912         xmlGenericError(xmlGenericErrorContext,
913                 "xmlBufAddHead: len < 0\n");
914 #endif
915         return -1;
916     }
917     if (len == 0) return 0;
918
919     if (len < 0)
920         len = xmlStrlen(str);
921
922     if (len <= 0) return -1;
923
924     if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
925         size_t start_buf = buf->content - buf->contentIO;
926
927         if (start_buf > (unsigned int) len) {
928             /*
929              * We can add it in the space previously shrinked
930              */
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);
937         }
938     }
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;
944         }
945     }
946
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;
953 }
954
955 /**
956  * xmlBufCat:
957  * @buf:  the buffer to add to
958  * @str:  the #xmlChar string
959  *
960  * Append a zero terminated string to an XML buffer.
961  *
962  * Returns 0 successful, a positive error code number otherwise
963  *         and -1 in case of internal or API error.
964  */
965 int
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);
973 }
974
975 /**
976  * xmlBufCCat:
977  * @buf:  the buffer to dump
978  * @str:  the C char string
979  *
980  * Append a zero terminated C string to an XML buffer.
981  *
982  * Returns 0 successful, a positive error code number otherwise
983  *         and -1 in case of internal or API error.
984  */
985 int
986 xmlBufCCat(xmlBufPtr buf, const char *str) {
987     const char *cur;
988
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;
999     }
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;
1005             }
1006         }
1007         buf->content[buf->use++] = *cur;
1008     }
1009     buf->content[buf->use] = 0;
1010     UPDATE_COMPAT(buf)
1011     return 0;
1012 }
1013
1014 /**
1015  * xmlBufWriteCHAR:
1016  * @buf:  the XML buffer
1017  * @string:  the string to add
1018  *
1019  * routine which manages and grows an output buffer. This one adds
1020  * xmlChars at the end of the buffer.
1021  *
1022  * Returns 0 if successful, a positive error code number otherwise
1023  *         and -1 in case of internal or API error.
1024  */
1025 int
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));
1033 }
1034
1035 /**
1036  * xmlBufWriteChar:
1037  * @buf:  the XML buffer output
1038  * @string:  the string to add
1039  *
1040  * routine which manage and grows an output buffer. This one add
1041  * C chars at the end of the array.
1042  *
1043  * Returns 0 if successful, a positive error code number otherwise
1044  *         and -1 in case of internal or API error.
1045  */
1046 int
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));
1054 }
1055
1056
1057 /**
1058  * xmlBufWriteQuotedString:
1059  * @buf:  the XML buffer output
1060  * @string:  the string to add
1061  *
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
1065  *
1066  * Returns 0 if successful, a positive error code number otherwise
1067  *         and -1 in case of internal or API error.
1068  */
1069 int
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;
1092                 }
1093                 else {
1094                     cur++;
1095                 }
1096             }
1097             if (base != cur)
1098                 xmlBufAdd(buf, base, cur - base);
1099             xmlBufCCat(buf, "\"");
1100         }
1101         else{
1102             xmlBufCCat(buf, "\'");
1103             xmlBufCat(buf, string);
1104             xmlBufCCat(buf, "\'");
1105         }
1106     } else {
1107         xmlBufCCat(buf, "\"");
1108         xmlBufCat(buf, string);
1109         xmlBufCCat(buf, "\"");
1110     }
1111     return(0);
1112 }
1113
1114 /**
1115  * xmlBufFromBuffer:
1116  * @buffer: incoming old buffer to convert to a new one
1117  *
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.
1122  *
1123  * Returns a new xmlBufPtr unless the call failed and NULL is returned
1124  */
1125 xmlBufPtr
1126 xmlBufFromBuffer(xmlBufferPtr buffer) {
1127     xmlBufPtr ret;
1128
1129     if (buffer == NULL)
1130         return(NULL);
1131
1132     ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
1133     if (ret == NULL) {
1134         xmlBufMemoryError(NULL, "creating buffer");
1135         return(NULL);
1136     }
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;
1146
1147     return(ret);
1148 }
1149
1150 /**
1151  * xmlBufBackToBuffer:
1152  * @buf: new buffer wrapping the old one
1153  *
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.
1159  *
1160  * Returns the old xmlBufferPtr unless the call failed and NULL is returned
1161  */
1162 xmlBufferPtr
1163 xmlBufBackToBuffer(xmlBufPtr buf) {
1164     xmlBufferPtr ret;
1165
1166     if ((buf == NULL) || (buf->error))
1167         return(NULL);
1168     CHECK_COMPAT(buf)
1169     if (buf->buffer == NULL) {
1170         xmlBufFree(buf);
1171         return(NULL);
1172     }
1173
1174     ret = buf->buffer;
1175     /*
1176      * What to do in case of error in the buffer ???
1177      */
1178     if (buf->use > INT_MAX) {
1179         /*
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.
1183          */
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) {
1188         /*
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.
1193          */
1194         xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
1195         ret->size = INT_MAX;
1196     }
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);
1204 }
1205
1206 /**
1207  * xmlBufMergeBuffer:
1208  * @buf: an xmlBufPtr
1209  * @buffer: the buffer to consume into @buf
1210  *
1211  * The content of @buffer is appended to @buf and @buffer is freed
1212  *
1213  * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
1214  */
1215 int
1216 xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
1217     int ret = 0;
1218
1219     if ((buf == NULL) || (buf->error)) {
1220         xmlBufferFree(buffer);
1221         return(-1);
1222     }
1223     CHECK_COMPAT(buf)
1224     if ((buffer != NULL) && (buffer->content != NULL) &&
1225              (buffer->use > 0)) {
1226         ret = xmlBufAdd(buf, buffer->content, buffer->use);
1227     }
1228     xmlBufferFree(buffer);
1229     return(ret);
1230 }
1231
1232 /**
1233  * xmlBufResetInput:
1234  * @buf: an xmlBufPtr
1235  * @input: an xmlParserInputPtr
1236  *
1237  * Update the input to use the current set of pointers from the buffer.
1238  *
1239  * Returns -1 in case of error, 0 otherwise
1240  */
1241 int
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);
1249 }
1250
1251 /**
1252  * xmlBufGetInputBase:
1253  * @buf: an xmlBufPtr
1254  * @input: an xmlParserInputPtr
1255  *
1256  * Get the base of the @input relative to the beginning of the buffer
1257  *
1258  * Returns the size_t corresponding to the displacement
1259  */
1260 size_t
1261 xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
1262     size_t base;
1263
1264     if ((input == NULL) || (buf == NULL) || (buf->error))
1265         return(-1);
1266     CHECK_COMPAT(buf)
1267     base = input->base - buf->content;
1268     /*
1269      * We could do some pointer arythmetic checks but that's probably
1270      * sufficient.
1271      */
1272     if (base > buf->size) {
1273         xmlBufOverflowError(buf, "Input reference outside of the buffer");
1274         base = 0;
1275     }
1276     return(base);
1277 }
1278
1279 /**
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
1285  *
1286  * Update the input to use the base and cur relative to the buffer
1287  * after a possible reallocation of its content
1288  *
1289  * Returns -1 in case of error, 0 otherwise
1290  */
1291 int
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);
1301 }
1302
1303 #define bottom_buf
1304 #include "elfgcchack.h"