/ libxml2 / buf.c
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 <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
  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
 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
 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      memset(ret->content, 0, (ret->size * sizeof(xmlChar)));
 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
 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          memset(ret->content, 0, (ret->size * sizeof(xmlChar)));
 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 *
 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
 231  xmlBufCreateStatic(void *mem, size_t size) {
 232      xmlBufPtr ret;
 233  
 234      if ((mem == NULL) || (size == 0))
 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
 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
 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
 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
 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
 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  	buf->size -= len;
 421      }
 422      UPDATE_COMPAT(buf)
 423      return(len);
 424  }
 425  
 426  /**
 427   * xmlBufGrowInternal:
 428   * @buf:  the buffer
 429   * @len:  the minimum free size to allocate
 430   *
 431   * Grow the available space of an XML buffer, @len is the target value
 432   * Error checking should be done on buf->error since using the return
 433   * value doesn't work that well
 434   *
 435   * Returns 0 in case of error or the length made available otherwise
 436   */
 437  static size_t
 438  xmlBufGrowInternal(xmlBufPtr buf, size_t len) {
 439      size_t size;
 440      xmlChar *newbuf;
 441  
 442      if ((buf == NULL) || (buf->error != 0)) return(0);
 443      CHECK_COMPAT(buf)
 444  
 445      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
 446      if (buf->use + len < buf->size)
 447          return(buf->size - buf->use);
 448  
 449      /*
 450       * Windows has a BIG problem on realloc timing, so we try to double
 451       * the buffer size (if that's enough) (bug 146697)
 452       * Apparently BSD too, and it's probably best for linux too
 453       * On an embedded system this may be something to change
 454       */
 455  #if 1
 456      if (buf->size > (size_t) len)
 457          size = buf->size * 2;
 458      else
 459          size = buf->use + len + 100;
 460  #else
 461      size = buf->use + len + 100;
 462  #endif
 463  
 464      if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
 465          /*
 466  	 * Used to provide parsing limits
 467  	 */
 468          if ((buf->use + len >= XML_MAX_TEXT_LENGTH) ||
 469  	    (buf->size >= XML_MAX_TEXT_LENGTH)) {
 470  	    xmlBufMemoryError(buf, "buffer error: text too long\n");
 471  	    return(0);
 472  	}
 473  	if (size >= XML_MAX_TEXT_LENGTH)
 474  	    size = XML_MAX_TEXT_LENGTH;
 475      }
 476      if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
 477          size_t start_buf = buf->content - buf->contentIO;
 478  
 479  	newbuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + size);
 480  	if (newbuf == NULL) {
 481  	    xmlBufMemoryError(buf, "growing buffer");
 482  	    return(0);
 483  	}
 484  	buf->contentIO = newbuf;
 485  	buf->content = newbuf + start_buf;
 486      } else {
 487  	newbuf = (xmlChar *) xmlRealloc(buf->content, size);
 488  	if (newbuf == NULL) {
 489  	    xmlBufMemoryError(buf, "growing buffer");
 490  	    return(0);
 491  	}
 492  	buf->content = newbuf;
 493      }
 494      buf->size = size;
 495      UPDATE_COMPAT(buf)
 496      return(buf->size - buf->use);
 497  }
 498  
 499  /**
 500   * xmlBufGrow:
 501   * @buf:  the buffer
 502   * @len:  the minimum free size to allocate
 503   *
 504   * Grow the available space of an XML buffer, @len is the target value
 505   * This is been kept compatible with xmlBufferGrow() as much as possible
 506   *
 507   * Returns -1 in case of error or the length made available otherwise
 508   */
 509  int
 510  xmlBufGrow(xmlBufPtr buf, int len) {
 511      size_t ret;
 512  
 513      if ((buf == NULL) || (len < 0)) return(-1);
 514      if (len == 0)
 515          return(0);
 516      ret = xmlBufGrowInternal(buf, len);
 517      if (buf->error != 0)
 518          return(-1);
 519      return((int) ret);
 520  }
 521  
 522  /**
 523   * xmlBufInflate:
 524   * @buf:  the buffer
 525   * @len:  the minimum extra free size to allocate
 526   *
 527   * Grow the available space of an XML buffer, adding at least @len bytes
 528   *
 529   * Returns 0 if successful or -1 in case of error
 530   */
 531  int
 532  xmlBufInflate(xmlBufPtr buf, size_t len) {
 533      if (buf == NULL) return(-1);
 534      xmlBufGrowInternal(buf, len + buf->size);
 535      if (buf->error)
 536          return(-1);
 537      return(0);
 538  }
 539  
 540  /**
 541   * xmlBufDump:
 542   * @file:  the file output
 543   * @buf:  the buffer to dump
 544   *
 545   * Dumps an XML buffer to  a FILE *.
 546   * Returns the number of #xmlChar written
 547   */
 548  size_t
 549  xmlBufDump(FILE *file, xmlBufPtr buf) {
 550      size_t ret;
 551  
 552      if ((buf == NULL) || (buf->error != 0)) {
 553  #ifdef DEBUG_BUFFER
 554          xmlGenericError(xmlGenericErrorContext,
 555  		"xmlBufDump: buf == NULL or in error\n");
 556  #endif
 557  	return(0);
 558      }
 559      if (buf->content == NULL) {
 560  #ifdef DEBUG_BUFFER
 561          xmlGenericError(xmlGenericErrorContext,
 562  		"xmlBufDump: buf->content == NULL\n");
 563  #endif
 564  	return(0);
 565      }
 566      CHECK_COMPAT(buf)
 567      if (file == NULL)
 568  	file = stdout;
 569      ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
 570      return(ret);
 571  }
 572  
 573  /**
 574   * xmlBufContent:
 575   * @buf:  the buffer
 576   *
 577   * Function to extract the content of a buffer
 578   *
 579   * Returns the internal content
 580   */
 581  
 582  xmlChar *
 583  xmlBufContent(const xmlBuf *buf)
 584  {
 585      if ((!buf) || (buf->error))
 586          return NULL;
 587  
 588      return(buf->content);
 589  }
 590  
 591  /**
 592   * xmlBufEnd:
 593   * @buf:  the buffer
 594   *
 595   * Function to extract the end of the content of a buffer
 596   *
 597   * Returns the end of the internal content or NULL in case of error
 598   */
 599  
 600  xmlChar *
 601  xmlBufEnd(xmlBufPtr buf)
 602  {
 603      if ((!buf) || (buf->error))
 604          return NULL;
 605      CHECK_COMPAT(buf)
 606  
 607      return(&buf->content[buf->use]);
 608  }
 609  
 610  /**
 611   * xmlBufAddLen:
 612   * @buf:  the buffer
 613   * @len:  the size which were added at the end
 614   *
 615   * Sometime data may be added at the end of the buffer without
 616   * using the xmlBuf APIs that is used to expand the used space
 617   * and set the zero terminating at the end of the buffer
 618   *
 619   * Returns -1 in case of error and 0 otherwise
 620   */
 621  int
 622  xmlBufAddLen(xmlBufPtr buf, size_t len) {
 623      if ((buf == NULL) || (buf->error))
 624          return(-1);
 625      CHECK_COMPAT(buf)
 626      if (len > (buf->size - buf->use))
 627          return(-1);
 628      buf->use += len;
 629      UPDATE_COMPAT(buf)
 630      if (buf->size > buf->use)
 631          buf->content[buf->use] = 0;
 632      else
 633          return(-1);
 634      return(0);
 635  }
 636  
 637  /**
 638   * xmlBufErase:
 639   * @buf:  the buffer
 640   * @len:  the size to erase at the end
 641   *
 642   * Sometime data need to be erased at the end of the buffer
 643   *
 644   * Returns -1 in case of error and 0 otherwise
 645   */
 646  int
 647  xmlBufErase(xmlBufPtr buf, size_t len) {
 648      if ((buf == NULL) || (buf->error))
 649          return(-1);
 650      CHECK_COMPAT(buf)
 651      if (len > buf->use)
 652          return(-1);
 653      buf->use -= len;
 654      buf->content[buf->use] = 0;
 655      UPDATE_COMPAT(buf)
 656      return(0);
 657  }
 658  
 659  /**
 660   * xmlBufLength:
 661   * @buf:  the buffer
 662   *
 663   * Function to get the length of a buffer
 664   *
 665   * Returns the length of data in the internal content
 666   */
 667  
 668  size_t
 669  xmlBufLength(const xmlBufPtr buf)
 670  {
 671      if ((!buf) || (buf->error))
 672          return 0;
 673      CHECK_COMPAT(buf)
 674  
 675      return(buf->use);
 676  }
 677  
 678  /**
 679   * xmlBufUse:
 680   * @buf:  the buffer
 681   *
 682   * Function to get the length of a buffer
 683   *
 684   * Returns the length of data in the internal content
 685   */
 686  
 687  size_t
 688  xmlBufUse(const xmlBufPtr buf)
 689  {
 690      if ((!buf) || (buf->error))
 691          return 0;
 692      CHECK_COMPAT(buf)
 693  
 694      return(buf->use);
 695  }
 696  
 697  /**
 698   * xmlBufAvail:
 699   * @buf:  the buffer
 700   *
 701   * Function to find how much free space is allocated but not
 702   * used in the buffer. It does not account for the terminating zero
 703   * usually needed
 704   *
 705   * Returns the amount or 0 if none or an error occurred
 706   */
 707  
 708  size_t
 709  xmlBufAvail(const xmlBufPtr buf)
 710  {
 711      if ((!buf) || (buf->error))
 712          return 0;
 713      CHECK_COMPAT(buf)
 714  
 715      return(buf->size - buf->use);
 716  }
 717  
 718  /**
 719   * xmlBufIsEmpty:
 720   * @buf:  the buffer
 721   *
 722   * Tell if a buffer is empty
 723   *
 724   * Returns 0 if no, 1 if yes and -1 in case of error
 725   */
 726  int
 727  xmlBufIsEmpty(const xmlBufPtr buf)
 728  {
 729      if ((!buf) || (buf->error))
 730          return(-1);
 731      CHECK_COMPAT(buf)
 732  
 733      return(buf->use == 0);
 734  }
 735  
 736  /**
 737   * xmlBufResize:
 738   * @buf:  the buffer to resize
 739   * @size:  the desired size
 740   *
 741   * Resize a buffer to accommodate minimum size of @size.
 742   *
 743   * Returns  0 in case of problems, 1 otherwise
 744   */
 745  int
 746  xmlBufResize(xmlBufPtr buf, size_t size)
 747  {
 748      unsigned int newSize;
 749      xmlChar* rebuf = NULL;
 750      size_t start_buf;
 751  
 752      if ((buf == NULL) || (buf->error))
 753          return(0);
 754      CHECK_COMPAT(buf)
 755  
 756      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return(0);
 757      if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
 758          /*
 759  	 * Used to provide parsing limits
 760  	 */
 761          if (size >= XML_MAX_TEXT_LENGTH) {
 762  	    xmlBufMemoryError(buf, "buffer error: text too long\n");
 763  	    return(0);
 764  	}
 765      }
 766  
 767      /* Don't resize if we don't have to */
 768      if (size < buf->size)
 769          return 1;
 770  
 771      /* figure out new size */
 772      switch (buf->alloc){
 773  	case XML_BUFFER_ALLOC_IO:
 774  	case XML_BUFFER_ALLOC_DOUBLEIT:
 775  	    /*take care of empty case*/
 776  	    newSize = (buf->size ? buf->size*2 : size + 10);
 777  	    while (size > newSize) {
 778  	        if (newSize > UINT_MAX / 2) {
 779  	            xmlBufMemoryError(buf, "growing buffer");
 780  	            return 0;
 781  	        }
 782  	        newSize *= 2;
 783  	    }
 784  	    break;
 785  	case XML_BUFFER_ALLOC_EXACT:
 786  	    newSize = size+10;
 787  	    break;
 788          case XML_BUFFER_ALLOC_HYBRID:
 789              if (buf->use < BASE_BUFFER_SIZE)
 790                  newSize = size;
 791              else {
 792                  newSize = buf->size * 2;
 793                  while (size > newSize) {
 794                      if (newSize > UINT_MAX / 2) {
 795                          xmlBufMemoryError(buf, "growing buffer");
 796                          return 0;
 797                      }
 798                      newSize *= 2;
 799                  }
 800              }
 801              break;
 802  
 803  	default:
 804  	    newSize = size+10;
 805  	    break;
 806      }
 807  
 808      if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
 809          start_buf = buf->content - buf->contentIO;
 810  
 811          if (start_buf > newSize) {
 812  	    /* move data back to start */
 813  	    memmove(buf->contentIO, buf->content, buf->use);
 814  	    buf->content = buf->contentIO;
 815  	    buf->content[buf->use] = 0;
 816  	    buf->size += start_buf;
 817  	} else {
 818  	    rebuf = (xmlChar *) xmlRealloc(buf->contentIO, start_buf + newSize);
 819  	    if (rebuf == NULL) {
 820  		xmlBufMemoryError(buf, "growing buffer");
 821  		return 0;
 822  	    }
 823  	    buf->contentIO = rebuf;
 824  	    buf->content = rebuf + start_buf;
 825  	}
 826      } else {
 827  	if (buf->content == NULL) {
 828  	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
 829  	} else if (buf->size - buf->use < 100) {
 830  	    rebuf = (xmlChar *) xmlRealloc(buf->content, newSize);
 831          } else {
 832  	    /*
 833  	     * if we are reallocating a buffer far from being full, it's
 834  	     * better to make a new allocation and copy only the used range
 835  	     * and free the old one.
 836  	     */
 837  	    rebuf = (xmlChar *) xmlMallocAtomic(newSize);
 838  	    if (rebuf != NULL) {
 839  		memcpy(rebuf, buf->content, buf->use);
 840  		xmlFree(buf->content);
 841  		rebuf[buf->use] = 0;
 842  	    }
 843  	}
 844  	if (rebuf == NULL) {
 845  	    xmlBufMemoryError(buf, "growing buffer");
 846  	    return 0;
 847  	}
 848  	buf->content = rebuf;
 849      }
 850      buf->size = newSize;
 851      UPDATE_COMPAT(buf)
 852  
 853      return 1;
 854  }
 855  
 856  /**
 857   * xmlBufAdd:
 858   * @buf:  the buffer to dump
 859   * @str:  the #xmlChar string
 860   * @len:  the number of #xmlChar to add
 861   *
 862   * Add a string range to an XML buffer. if len == -1, the length of
 863   * str is recomputed.
 864   *
 865   * Returns 0 successful, a positive error code number otherwise
 866   *         and -1 in case of internal or API error.
 867   */
 868  int
 869  xmlBufAdd(xmlBufPtr buf, const xmlChar *str, int len) {
 870      unsigned int needSize;
 871  
 872      if ((str == NULL) || (buf == NULL) || (buf->error))
 873  	return -1;
 874      CHECK_COMPAT(buf)
 875  
 876      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
 877      if (len < -1) {
 878  #ifdef DEBUG_BUFFER
 879          xmlGenericError(xmlGenericErrorContext,
 880  		"xmlBufAdd: len < 0\n");
 881  #endif
 882  	return -1;
 883      }
 884      if (len == 0) return 0;
 885  
 886      if (len < 0)
 887          len = xmlStrlen(str);
 888  
 889      if (len < 0) return -1;
 890      if (len == 0) return 0;
 891  
 892      needSize = buf->use + len + 2;
 893      if (needSize > buf->size){
 894  	if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
 895  	    /*
 896  	     * Used to provide parsing limits
 897  	     */
 898  	    if (needSize >= XML_MAX_TEXT_LENGTH) {
 899  		xmlBufMemoryError(buf, "buffer error: text too long\n");
 900  		return(-1);
 901  	    }
 902  	}
 903          if (!xmlBufResize(buf, needSize)){
 904  	    xmlBufMemoryError(buf, "growing buffer");
 905              return XML_ERR_NO_MEMORY;
 906          }
 907      }
 908  
 909      memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
 910      buf->use += len;
 911      buf->content[buf->use] = 0;
 912      UPDATE_COMPAT(buf)
 913      return 0;
 914  }
 915  
 916  /**
 917   * xmlBufAddHead:
 918   * @buf:  the buffer
 919   * @str:  the #xmlChar string
 920   * @len:  the number of #xmlChar to add
 921   *
 922   * Add a string range to the beginning of an XML buffer.
 923   * if len == -1, the length of @str is recomputed.
 924   *
 925   * Returns 0 successful, a positive error code number otherwise
 926   *         and -1 in case of internal or API error.
 927   */
 928  int
 929  xmlBufAddHead(xmlBufPtr buf, const xmlChar *str, int len) {
 930      unsigned int needSize;
 931  
 932      if ((buf == NULL) || (buf->error))
 933          return(-1);
 934      CHECK_COMPAT(buf)
 935      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
 936      if (str == NULL) {
 937  #ifdef DEBUG_BUFFER
 938          xmlGenericError(xmlGenericErrorContext,
 939  		"xmlBufAddHead: str == NULL\n");
 940  #endif
 941  	return -1;
 942      }
 943      if (len < -1) {
 944  #ifdef DEBUG_BUFFER
 945          xmlGenericError(xmlGenericErrorContext,
 946  		"xmlBufAddHead: len < 0\n");
 947  #endif
 948  	return -1;
 949      }
 950      if (len == 0) return 0;
 951  
 952      if (len < 0)
 953          len = xmlStrlen(str);
 954  
 955      if (len <= 0) return -1;
 956  
 957      if ((buf->alloc == XML_BUFFER_ALLOC_IO) && (buf->contentIO != NULL)) {
 958          size_t start_buf = buf->content - buf->contentIO;
 959  
 960  	if (start_buf > (unsigned int) len) {
 961  	    /*
 962  	     * We can add it in the space previously shrinked
 963  	     */
 964  	    buf->content -= len;
 965              memmove(&buf->content[0], str, len);
 966  	    buf->use += len;
 967  	    buf->size += len;
 968  	    UPDATE_COMPAT(buf)
 969  	    return(0);
 970  	}
 971      }
 972      needSize = buf->use + len + 2;
 973      if (needSize > buf->size){
 974  	if (buf->alloc == XML_BUFFER_ALLOC_BOUNDED) {
 975  	    /*
 976  	     * Used to provide parsing limits
 977  	     */
 978  	    if (needSize >= XML_MAX_TEXT_LENGTH) {
 979  		xmlBufMemoryError(buf, "buffer error: text too long\n");
 980  		return(-1);
 981  	    }
 982  	}
 983          if (!xmlBufResize(buf, needSize)){
 984  	    xmlBufMemoryError(buf, "growing buffer");
 985              return XML_ERR_NO_MEMORY;
 986          }
 987      }
 988  
 989      memmove(&buf->content[len], &buf->content[0], buf->use);
 990      memmove(&buf->content[0], str, len);
 991      buf->use += len;
 992      buf->content[buf->use] = 0;
 993      UPDATE_COMPAT(buf)
 994      return 0;
 995  }
 996  
 997  /**
 998   * xmlBufCat:
 999   * @buf:  the buffer to add to
1000   * @str:  the #xmlChar string
1001   *
1002   * Append a zero terminated string to an XML buffer.
1003   *
1004   * Returns 0 successful, a positive error code number otherwise
1005   *         and -1 in case of internal or API error.
1006   */
1007  int
1008  xmlBufCat(xmlBufPtr buf, const xmlChar *str) {
1009      if ((buf == NULL) || (buf->error))
1010          return(-1);
1011      CHECK_COMPAT(buf)
1012      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1013      if (str == NULL) return -1;
1014      return xmlBufAdd(buf, str, -1);
1015  }
1016  
1017  /**
1018   * xmlBufCCat:
1019   * @buf:  the buffer to dump
1020   * @str:  the C char string
1021   *
1022   * Append a zero terminated C string to an XML buffer.
1023   *
1024   * Returns 0 successful, a positive error code number otherwise
1025   *         and -1 in case of internal or API error.
1026   */
1027  int
1028  xmlBufCCat(xmlBufPtr buf, const char *str) {
1029      const char *cur;
1030  
1031      if ((buf == NULL) || (buf->error))
1032          return(-1);
1033      CHECK_COMPAT(buf)
1034      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE) return -1;
1035      if (str == NULL) {
1036  #ifdef DEBUG_BUFFER
1037          xmlGenericError(xmlGenericErrorContext,
1038  		"xmlBufCCat: str == NULL\n");
1039  #endif
1040  	return -1;
1041      }
1042      for (cur = str;*cur != 0;cur++) {
1043          if (buf->use  + 10 >= buf->size) {
1044              if (!xmlBufResize(buf, buf->use+10)){
1045  		xmlBufMemoryError(buf, "growing buffer");
1046                  return XML_ERR_NO_MEMORY;
1047              }
1048          }
1049          buf->content[buf->use++] = *cur;
1050      }
1051      buf->content[buf->use] = 0;
1052      UPDATE_COMPAT(buf)
1053      return 0;
1054  }
1055  
1056  /**
1057   * xmlBufWriteCHAR:
1058   * @buf:  the XML buffer
1059   * @string:  the string to add
1060   *
1061   * routine which manages and grows an output buffer. This one adds
1062   * xmlChars at the end of the buffer.
1063   *
1064   * Returns 0 if successful, a positive error code number otherwise
1065   *         and -1 in case of internal or API error.
1066   */
1067  int
1068  xmlBufWriteCHAR(xmlBufPtr buf, const xmlChar *string) {
1069      if ((buf == NULL) || (buf->error))
1070          return(-1);
1071      CHECK_COMPAT(buf)
1072      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1073          return(-1);
1074      return(xmlBufCat(buf, string));
1075  }
1076  
1077  /**
1078   * xmlBufWriteChar:
1079   * @buf:  the XML buffer output
1080   * @string:  the string to add
1081   *
1082   * routine which manage and grows an output buffer. This one add
1083   * C chars at the end of the array.
1084   *
1085   * Returns 0 if successful, a positive error code number otherwise
1086   *         and -1 in case of internal or API error.
1087   */
1088  int
1089  xmlBufWriteChar(xmlBufPtr buf, const char *string) {
1090      if ((buf == NULL) || (buf->error))
1091          return(-1);
1092      CHECK_COMPAT(buf)
1093      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1094          return(-1);
1095      return(xmlBufCCat(buf, string));
1096  }
1097  
1098  
1099  /**
1100   * xmlBufWriteQuotedString:
1101   * @buf:  the XML buffer output
1102   * @string:  the string to add
1103   *
1104   * routine which manage and grows an output buffer. This one writes
1105   * a quoted or double quoted #xmlChar string, checking first if it holds
1106   * quote or double-quotes internally
1107   *
1108   * Returns 0 if successful, a positive error code number otherwise
1109   *         and -1 in case of internal or API error.
1110   */
1111  int
1112  xmlBufWriteQuotedString(xmlBufPtr buf, const xmlChar *string) {
1113      const xmlChar *cur, *base;
1114      if ((buf == NULL) || (buf->error))
1115          return(-1);
1116      CHECK_COMPAT(buf)
1117      if (buf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)
1118          return(-1);
1119      if (xmlStrchr(string, '\"')) {
1120          if (xmlStrchr(string, '\'')) {
1121  #ifdef DEBUG_BUFFER
1122  	    xmlGenericError(xmlGenericErrorContext,
1123   "xmlBufWriteQuotedString: string contains quote and double-quotes !\n");
1124  #endif
1125  	    xmlBufCCat(buf, "\"");
1126              base = cur = string;
1127              while(*cur != 0){
1128                  if(*cur == '"'){
1129                      if (base != cur)
1130                          xmlBufAdd(buf, base, cur - base);
1131                      xmlBufAdd(buf, BAD_CAST "&quot;", 6);
1132                      cur++;
1133                      base = cur;
1134                  }
1135                  else {
1136                      cur++;
1137                  }
1138              }
1139              if (base != cur)
1140                  xmlBufAdd(buf, base, cur - base);
1141  	    xmlBufCCat(buf, "\"");
1142  	}
1143          else{
1144  	    xmlBufCCat(buf, "\'");
1145              xmlBufCat(buf, string);
1146  	    xmlBufCCat(buf, "\'");
1147          }
1148      } else {
1149          xmlBufCCat(buf, "\"");
1150          xmlBufCat(buf, string);
1151          xmlBufCCat(buf, "\"");
1152      }
1153      return(0);
1154  }
1155  
1156  /**
1157   * xmlBufFromBuffer:
1158   * @buffer: incoming old buffer to convert to a new one
1159   *
1160   * Helper routine to switch from the old buffer structures in use
1161   * in various APIs. It creates a wrapper xmlBufPtr which will be
1162   * used for internal processing until the xmlBufBackToBuffer() is
1163   * issued.
1164   *
1165   * Returns a new xmlBufPtr unless the call failed and NULL is returned
1166   */
1167  xmlBufPtr
1168  xmlBufFromBuffer(xmlBufferPtr buffer) {
1169      xmlBufPtr ret;
1170  
1171      if (buffer == NULL)
1172          return(NULL);
1173  
1174      ret = (xmlBufPtr) xmlMalloc(sizeof(xmlBuf));
1175      if (ret == NULL) {
1176  	xmlBufMemoryError(NULL, "creating buffer");
1177          return(NULL);
1178      }
1179      ret->use = buffer->use;
1180      ret->size = buffer->size;
1181      ret->compat_use = buffer->use;
1182      ret->compat_size = buffer->size;
1183      ret->error = 0;
1184      ret->buffer = buffer;
1185      ret->alloc = buffer->alloc;
1186      ret->content = buffer->content;
1187      ret->contentIO = buffer->contentIO;
1188  
1189      return(ret);
1190  }
1191  
1192  /**
1193   * xmlBufBackToBuffer:
1194   * @buf: new buffer wrapping the old one
1195   *
1196   * Function to be called once internal processing had been done to
1197   * update back the buffer provided by the user. This can lead to
1198   * a failure in case the size accumulated in the xmlBuf is larger
1199   * than what an xmlBuffer can support on 64 bits (INT_MAX)
1200   * The xmlBufPtr @buf wrapper is deallocated by this call in any case.
1201   *
1202   * Returns the old xmlBufferPtr unless the call failed and NULL is returned
1203   */
1204  xmlBufferPtr
1205  xmlBufBackToBuffer(xmlBufPtr buf) {
1206      xmlBufferPtr ret;
1207  
1208      if ((buf == NULL) || (buf->error))
1209          return(NULL);
1210      CHECK_COMPAT(buf)
1211      if (buf->buffer == NULL) {
1212          xmlBufFree(buf);
1213          return(NULL);
1214      }
1215  
1216      ret = buf->buffer;
1217      /*
1218       * What to do in case of error in the buffer ???
1219       */
1220      if (buf->use > INT_MAX) {
1221          /*
1222           * Worse case, we really allocated and used more than the
1223           * maximum allowed memory for an xmlBuffer on this architecture.
1224           * Keep the buffer but provide a truncated size value.
1225           */
1226          xmlBufOverflowError(buf, "Used size too big for xmlBuffer");
1227          ret->use = INT_MAX;
1228          ret->size = INT_MAX;
1229      } else if (buf->size > INT_MAX) {
1230          /*
1231           * milder case, we allocated more than the maximum allowed memory
1232           * for an xmlBuffer on this architecture, but used less than the
1233           * limit.
1234           * Keep the buffer but provide a truncated size value.
1235           */
1236          xmlBufOverflowError(buf, "Allocated size too big for xmlBuffer");
1237          ret->use = (int) buf->use;
1238          ret->size = INT_MAX;
1239      } else {
1240          ret->use = (int) buf->use;
1241          ret->size = (int) buf->size;
1242      }
1243      ret->alloc = buf->alloc;
1244      ret->content = buf->content;
1245      ret->contentIO = buf->contentIO;
1246      xmlFree(buf);
1247      return(ret);
1248  }
1249  
1250  /**
1251   * xmlBufMergeBuffer:
1252   * @buf: an xmlBufPtr
1253   * @buffer: the buffer to consume into @buf
1254   *
1255   * The content of @buffer is appended to @buf and @buffer is freed
1256   *
1257   * Returns -1 in case of error, 0 otherwise, in any case @buffer is freed
1258   */
1259  int
1260  xmlBufMergeBuffer(xmlBufPtr buf, xmlBufferPtr buffer) {
1261      int ret = 0;
1262  
1263      if ((buf == NULL) || (buf->error)) {
1264  	xmlBufferFree(buffer);
1265          return(-1);
1266      }
1267      CHECK_COMPAT(buf)
1268      if ((buffer != NULL) && (buffer->content != NULL) &&
1269               (buffer->use > 0)) {
1270          ret = xmlBufAdd(buf, buffer->content, buffer->use);
1271      }
1272      xmlBufferFree(buffer);
1273      return(ret);
1274  }
1275  
1276  /**
1277   * xmlBufResetInput:
1278   * @buf: an xmlBufPtr
1279   * @input: an xmlParserInputPtr
1280   *
1281   * Update the input to use the current set of pointers from the buffer.
1282   *
1283   * Returns -1 in case of error, 0 otherwise
1284   */
1285  int
1286  xmlBufResetInput(xmlBufPtr buf, xmlParserInputPtr input) {
1287      if ((input == NULL) || (buf == NULL) || (buf->error))
1288          return(-1);
1289      CHECK_COMPAT(buf)
1290      input->base = input->cur = buf->content;
1291      input->end = &buf->content[buf->use];
1292      return(0);
1293  }
1294  
1295  /**
1296   * xmlBufGetInputBase:
1297   * @buf: an xmlBufPtr
1298   * @input: an xmlParserInputPtr
1299   *
1300   * Get the base of the @input relative to the beginning of the buffer
1301   *
1302   * Returns the size_t corresponding to the displacement
1303   */
1304  size_t
1305  xmlBufGetInputBase(xmlBufPtr buf, xmlParserInputPtr input) {
1306      size_t base;
1307  
1308      if ((input == NULL) || (buf == NULL) || (buf->error))
1309          return(-1);
1310      CHECK_COMPAT(buf)
1311      base = input->base - buf->content;
1312      /*
1313       * We could do some pointer arythmetic checks but that's probably
1314       * sufficient.
1315       */
1316      if (base > buf->size) {
1317          xmlBufOverflowError(buf, "Input reference outside of the buffer");
1318          base = 0;
1319      }
1320      return(base);
1321  }
1322  
1323  /**
1324   * xmlBufSetInputBaseCur:
1325   * @buf: an xmlBufPtr
1326   * @input: an xmlParserInputPtr
1327   * @base: the base value relative to the beginning of the buffer
1328   * @cur: the cur value relative to the beginning of the buffer
1329   *
1330   * Update the input to use the base and cur relative to the buffer
1331   * after a possible reallocation of its content
1332   *
1333   * Returns -1 in case of error, 0 otherwise
1334   */
1335  int
1336  xmlBufSetInputBaseCur(xmlBufPtr buf, xmlParserInputPtr input,
1337                        size_t base, size_t cur) {
1338      if (input == NULL)
1339          return(-1);
1340      if ((buf == NULL) || (buf->error)) {
1341          input->base = input->cur = input->end = BAD_CAST "";
1342          return(-1);
1343      }
1344      CHECK_COMPAT(buf)
1345      input->base = &buf->content[base];
1346      input->cur = input->base + cur;
1347      input->end = &buf->content[buf->use];
1348      return(0);
1349  }
1350  
1351  #define bottom_buf
1352  #include "elfgcchack.h"