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