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