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