Home | History | Annotate | Download | only in libxml2
      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 (at) 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     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
    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 *
    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)
    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     }
    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
    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
    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
    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
    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 *
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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