X-Git-Url: http://git.silcnet.org/gitweb/?p=crypto.git;a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcbuffer.h;h=3a3db7b679ffc7283060054813544fc80e2b69a7;hp=673c4a7ff0608da0bd421c4f42be134060c5c313;hb=38b10925eeea619c2b6fa646892df4416e6dd08f;hpb=f3b43606c546a86a43b283b46464972296e1e271 diff --git a/lib/silcutil/silcbuffer.h b/lib/silcutil/silcbuffer.h index 673c4a7f..3a3db7b6 100644 --- a/lib/silcutil/silcbuffer.h +++ b/lib/silcutil/silcbuffer.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1998 - 2006 Pekka Riikonen + Copyright (C) 1998 - 2008 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -110,7 +110,7 @@ * * SOURCE */ -typedef struct { +typedef struct SilcBufferObject { unsigned char *head; unsigned char *data; unsigned char *tail; @@ -120,106 +120,114 @@ typedef struct { /* Macros */ -/****d* silcutil/SilcBufferAPI/silc_buffer_truelen +/****f* silcutil/SilcBufferAPI/silc_buffer_data * * NAME * - * SilcUInt32 silc_buffer_truelen(SilcBuffer sb) + * unsigned char *silc_buffer_data(SilcBuffer sb) * * DESCRIPTION * - * Returns the true length of the buffer. + * Returns pointer to the data area of the buffer. * * SOURCE */ -#define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head) +#define silc_buffer_data(x) (x)->data /***/ -/****d* silcutil/SilcBufferAPI/silc_buffer_len +/****f* silcutil/SilcBufferAPI/silc_buffer_datalen * * NAME * - * SilcUInt32 silc_buffer_len(SilcBuffer sb) + * #define silc_buffer_datalen ... * * DESCRIPTION * - * Returns the current length of the data area of the buffer. + * Macro that can be used in function argument list to give the data + * pointer and the data length, instead of calling both silc_buffer_data + * and silc_buffer_len separately. + * + * EXAMPLE + * + * // Following are the same thing + * silc_foo_function(foo, silc_buffer_datalen(buf)); + * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf)); * * SOURCE */ -#define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data) +#define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \ + (x) ? silc_buffer_len((x)) : 0 /***/ -/****d* silcutil/SilcBufferAPI/silc_buffer_headlen +/* Inline functions */ + +/****d* silcutil/SilcBufferAPI/silc_buffer_truelen * * NAME * - * SilcUInt32 silc_buffer_headlen(SilcBuffer sb) + * SilcUInt32 silc_buffer_truelen(SilcBuffer sb) * * DESCRIPTION * - * Returns the current length of the head data area of the buffer. + * Returns the true length of the buffer. * - * SOURCE - */ -#define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head) -/***/ + ***/ +static inline +SilcUInt32 silc_buffer_truelen(SilcBuffer x) +{ + return (SilcUInt32)(x->end - x->head); +} -/****d* silcutil/SilcBufferAPI/silc_buffer_taillen +/****d* silcutil/SilcBufferAPI/silc_buffer_len * * NAME * - * SilcUInt32 silc_buffer_taillen(SilcBuffer sb) + * SilcUInt32 silc_buffer_len(SilcBuffer sb) * * DESCRIPTION * - * Returns the current length of the tail data area of the buffer. + * Returns the current length of the data area of the buffer. * - * SOURCE - */ -#define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail) -/***/ + ***/ +static inline +SilcUInt32 silc_buffer_len(SilcBuffer x) +{ + return (SilcUInt32)(x->tail - x->data); +} -/****f* silcutil/SilcBufferAPI/silc_buffer_data +/****d* silcutil/SilcBufferAPI/silc_buffer_headlen * * NAME * - * unsigned char *silc_buffer_data(SilcBuffer sb) + * SilcUInt32 silc_buffer_headlen(SilcBuffer sb) * * DESCRIPTION * - * Returns pointer to the data area of the buffer. + * Returns the current length of the head data area of the buffer. * - * SOURCE - */ -#define silc_buffer_data(x) (x)->data -/***/ + ***/ +static inline +SilcUInt32 silc_buffer_headlen(SilcBuffer x) +{ + return (SilcUInt32)(x->data - x->head); +} -/****f* silcutil/SilcBufferAPI/silc_buffer_datalen +/****d* silcutil/SilcBufferAPI/silc_buffer_taillen * * NAME * - * #define silc_buffer_datalen ... + * SilcUInt32 silc_buffer_taillen(SilcBuffer sb) * * DESCRIPTION * - * Macro that can be used in function argument list to give the data - * pointer and the data length, instead of calling both silc_buffer_data - * and silc_buffer_len separately. - * - * EXAMPLE - * - * // Following are the same thing - * silc_foo_function(foo, silc_buffer_datalen(buf)); - * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf)); + * Returns the current length of the tail data area of the buffer. * - * SOURCE - */ -#define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \ - (x) ? silc_buffer_len((x)) : 0 -/***/ - -/* Inline functions */ + ***/ +static inline +SilcUInt32 silc_buffer_taillen(SilcBuffer x) +{ + return (SilcUInt32)(x->end - x->tail); +} /****f* silcutil/SilcBufferAPI/silc_buffer_alloc * @@ -230,7 +238,8 @@ typedef struct { * * DESCRIPTION * - * Allocates new SilcBuffer and returns it. Returns NULL on error. + * Allocates new SilcBuffer and returns it. Returns NULL if system is + * out of memory. * ***/ @@ -246,7 +255,55 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len) if (silc_likely(len)) { /* Allocate the actual data area */ - sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head)); + sb->head = (unsigned char *)silc_malloc(len * sizeof(*sb->head)); + if (silc_unlikely(!sb->head)) + return NULL; + + /* Set pointers to the new buffer */ + sb->data = sb->head; + sb->tail = sb->head; + sb->end = sb->head + len; + } + + return sb; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_salloc + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len); + * + * DESCRIPTION + * + * Allocates new SilcBuffer and returns it. Returns NULL if system is + * out of memory. + * + * This routine use SilcStack are memory source. If `stack' is NULL + * reverts back to normal allocating routine. + * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * + ***/ + +static inline +SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len) +{ + SilcBuffer sb; + + if (!stack) + return silc_buffer_alloc(len); + + /* Allocate new SilcBuffer */ + sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb)); + if (silc_unlikely(!sb)) + return NULL; + + if (silc_likely(len)) { + /* Allocate the actual data area */ + sb->head = (unsigned char *)silc_smalloc(stack, len * sizeof(*sb->head)); if (silc_unlikely(!sb->head)) return NULL; @@ -274,6 +331,7 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len) * * Must not be called for buffers allocated with silc_buffer_salloc, * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone. + * Call silc_buffer_sfree instead. * ***/ @@ -290,6 +348,37 @@ void silc_buffer_free(SilcBuffer sb) } } +/****f* silcutil/SilcBufferAPI/silc_buffer_sfree + * + * SYNOPSIS + * + * static inline + * void silc_buffer_free(SilcStack stack, SilcBuffer sb); + * + * DESCRIPTION + * + * Frees SilcBuffer. If `stack' is NULL this calls silc_buffer_free. Can + * be called safely `sb' as NULL. + * + ***/ + +static inline +void silc_buffer_sfree(SilcStack stack, SilcBuffer sb) +{ + if (stack) { +#ifdef SILC_DEBUG + if (sb) { + if (sb->head) + memset(sb->head, 'F', silc_buffer_truelen(sb)); + memset(sb, 'F', sizeof(*sb)); + } +#endif /* SILC_DEBUG */ + return; + } + + silc_buffer_free(sb); +} + /****f* silcutil/SilcBufferAPI/silc_buffer_steal * * SYNOPSIS @@ -335,6 +424,7 @@ unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len) * * Must not be called for buffers allocated with silc_buffer_salloc, * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone. + * Use silc_buffer_spurge instead. * ***/ @@ -344,6 +434,36 @@ void silc_buffer_purge(SilcBuffer sb) silc_free(silc_buffer_steal(sb, NULL)); } +/****f* silcutil/SilcBufferAPI/silc_buffer_spurge + * + * SYNOPSIS + * + * static inline + * void silc_buffer_spurge(SilcStack stack, SilcBuffer sb); + * + * DESCRIPTION + * + * Same as silc_buffer_free but free's only the contents of the buffer + * not the buffer itself. The `sb' remains intact, data is freed. Buffer + * is ready for re-use after calling this function. If `stack' is NULL + * this calls silc_buffer_purge. + * + ***/ + +static inline +void silc_buffer_spurge(SilcStack stack, SilcBuffer sb) +{ + if (stack) { +#ifdef SILC_DEBUG + if (sb && sb->head) + memset(silc_buffer_steal(sb, NULL), 'F', silc_buffer_truelen(sb)); +#endif /* SILC_DEBUG */ + return; + } + + silc_buffer_purge(sb); +} + /****f* silcutil/SilcBufferAPI/silc_buffer_set * * SYNOPSIS @@ -385,7 +505,8 @@ void silc_buffer_set(SilcBuffer sb, unsigned char *data, SilcUInt32 data_len) * * Pulls current data area towards end. The length of the currently * valid data area is also decremented. Returns pointer to the data - * area before pulling. Returns NULL on error. + * area before pulling. Returns NULL if the pull would lead to buffer + * overflow or would go beyond the valid data area. * * EXAMPLE * @@ -408,12 +529,15 @@ static inline unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_data = sb->data; -#if defined(SILC_DEBUG) + +#ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_len(sb)); -#else - if (silc_unlikely(len > silc_buffer_len(sb))) +#endif /* SILC_DIST_INPLACE */ + if (silc_unlikely(len > silc_buffer_len(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; -#endif + } + sb->data += len; return old_data; } @@ -429,7 +553,8 @@ unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len) * * Pushes current data area towards beginning. Length of the currently * valid data area is also incremented. Returns a pointer to the - * data area before pushing. Returns NULL on error. + * data area before pushing. Returns NULL if the push would lead to + * buffer underflow or would go under the valid data area. * * EXAMPLE * @@ -452,12 +577,15 @@ static inline unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_data = sb->data; -#if defined(SILC_DEBUG) + +#ifdef SILC_DIST_INPLACE SILC_ASSERT((sb->data - len) >= sb->head); -#else - if (silc_unlikely((sb->data - len) < sb->head)) +#endif /* SILC_DIST_INPLACE */ + if (silc_unlikely((sb->data - len) < sb->head)) { + silc_set_errno(SILC_ERR_UNDERFLOW); return NULL; -#endif + } + sb->data -= len; return old_data; } @@ -473,7 +601,7 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len) * * Pulls current tail section towards end. Length of the current valid * data area is also incremented. Returns a pointer to the data area - * before pulling. Returns NULL on error. + * before pulling. Returns NULL if the pull would lead to buffer overflow. * * EXAMPLE * @@ -496,12 +624,15 @@ static inline unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_tail = sb->tail; -#if defined(SILC_DEBUG) + +#ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_taillen(sb)); -#else - if (silc_unlikely(len > silc_buffer_taillen(sb))) +#endif /* SILC_DIST_INPLACE */ + if (silc_unlikely(len > silc_buffer_taillen(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; -#endif + } + sb->tail += len; return old_tail; } @@ -517,7 +648,8 @@ unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len) * * Pushes current tail section towards beginning. Length of the current * valid data area is also decremented. Returns a pointer to the - * tail section before pushing. Returns NULL on error. + * tail section before pushing. Returns NULL if the push would lead to + * buffer underflow or go under valid tail area. * * EXAMPLE * @@ -540,12 +672,15 @@ static inline unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_tail = sb->tail; -#if defined(SILC_DEBUG) + +#ifdef SILC_DIST_INPLACE SILC_ASSERT((sb->tail - len) >= sb->data); -#else - if (silc_unlikely((sb->tail - len) < sb->data)) +#endif /* SILC_DIST_INPLACE */ + if (silc_unlikely((sb->tail - len) < sb->data)) { + silc_set_errno(SILC_ERR_UNDERFLOW); return NULL; -#endif + } + sb->tail -= len; return old_tail; } @@ -562,7 +697,8 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len) * DESCRIPTION * * Puts data at the head of the buffer. Returns pointer to the copied - * data area. Returns NULL on error. + * data area. Returns NULL if the data is longer that the current head + * area. * * EXAMPLE * @@ -581,12 +717,22 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb, const unsigned char *data, SilcUInt32 len) { -#if defined(SILC_DEBUG) +#ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_headlen(sb)); -#else - if (silc_unlikely(len > silc_buffer_headlen(sb))) +#endif /* SILC_DIST_INPLACE */ + if (silc_unlikely(len > silc_buffer_headlen(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; -#endif + } + + if (sb->head > data) { + if (sb->head - data <= len) + return (unsigned char *)memmove(sb->head, data, len); + } else { + if (data - sb->head <= len) + return (unsigned char *)memmove(sb->head, data, len); + } + return (unsigned char *)memcpy(sb->head, data, len); } @@ -602,7 +748,8 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb, * DESCRIPTION * * Puts data at the start of the valid data area. Returns a pointer - * to the copied data area. Returns NULL on error. + * to the copied data area. Returns NULL if the data is longer than the + * current data area. * * EXAMPLE * @@ -621,12 +768,22 @@ unsigned char *silc_buffer_put(SilcBuffer sb, const unsigned char *data, SilcUInt32 len) { -#if defined(SILC_DEBUG) +#ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_len(sb)); -#else - if (silc_unlikely(len > silc_buffer_len(sb))) +#endif /* SILC_DIST_INPLACE */ + if (silc_unlikely(len > silc_buffer_len(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; -#endif + } + + if (sb->data > data) { + if (sb->data - data <= len) + return (unsigned char *)memmove(sb->data, data, len); + } else { + if (data - sb->data <= len) + return (unsigned char *)memmove(sb->data, data, len); + } + return (unsigned char *)memcpy(sb->data, data, len); } @@ -642,7 +799,8 @@ unsigned char *silc_buffer_put(SilcBuffer sb, * DESCRIPTION * * Puts data at the tail of the buffer. Returns pointer to the copied - * data area. Returns NULL on error. + * data area. Returns NULL if the data is longer than the current tail + * area. * * EXAMPLE * @@ -661,12 +819,22 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb, const unsigned char *data, SilcUInt32 len) { -#if defined(SILC_DEBUG) +#ifdef SILC_DIST_INPLACE SILC_ASSERT(len <= silc_buffer_taillen(sb)); -#else - if (silc_unlikely(len > silc_buffer_taillen(sb))) +#endif /* SILC_DIST_INPLACE */ + if (silc_unlikely(len > silc_buffer_taillen(sb))) { + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; -#endif + } + + if (sb->tail > data) { + if (sb->tail - data <= len) + return (unsigned char *)memmove(sb->tail, data, len); + } else { + if (data - sb->tail <= len) + return (unsigned char *)memmove(sb->tail, data, len); + } + return (unsigned char *)memcpy(sb->tail, data, len); } @@ -681,7 +849,7 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb, * * Allocates `len' bytes size buffer and moves the tail area automatically * `len' bytes so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. Returns NULL on error. + * silc_buffer_pull_tail. Returns NULL if system is out of memory. * ***/ @@ -695,6 +863,37 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len) return sb; } +/****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len); + * + * DESCRIPTION + * + * Allocates `len' bytes size buffer and moves the tail area automatically + * `len' bytes so that the buffer is ready to use without calling the + * silc_buffer_pull_tail. Returns NULL if system is out of memory. + * + * This routine use SilcStack are memory source. If `stack' is NULL + * reverts back to normal allocating routine. + * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * + ***/ + +static inline +SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len) +{ + SilcBuffer sb = silc_buffer_salloc(stack, len); + if (silc_unlikely(!sb)) + return NULL; + silc_buffer_pull_tail(sb, len); + return sb; +} + /****f* silcutil/SilcBufferAPI/silc_buffer_reset * * SYNOPSIS @@ -790,7 +989,7 @@ void silc_buffer_end(SilcBuffer sb) * * Generates copy of a SilcBuffer. This copies everything inside the * currently valid data area, nothing more. Use silc_buffer_clone to - * copy entire buffer. Returns NULL on error. + * copy entire buffer. Returns NULL if system is out of memory. * ***/ @@ -807,205 +1006,144 @@ SilcBuffer silc_buffer_copy(SilcBuffer sb) return sb_new; } -/****f* silcutil/SilcBufferAPI/silc_buffer_clone +/****f* silcutil/SilcBufferAPI/silc_buffer_scopy * * SYNOPSIS * * static inline - * SilcBuffer silc_buffer_clone(SilcBuffer sb); + * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb); * * DESCRIPTION * - * Clones SilcBuffer. This generates new SilcBuffer and copies - * everything from the source buffer. The result is exact clone of - * the original buffer. Returns NULL on error. + * Generates copy of a SilcBuffer. This copies everything inside the + * currently valid data area, nothing more. Use silc_buffer_clone to + * copy entire buffer. Returns NULL if system is out of memory. + * + * This routine use SilcStack are memory source. If `stack' is NULL + * reverts back to normal allocating routine. + * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. * ***/ static inline -SilcBuffer silc_buffer_clone(SilcBuffer sb) +SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb) { SilcBuffer sb_new; - sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb)); + sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb)); if (silc_unlikely(!sb_new)) return NULL; - silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb)); - sb_new->data = sb_new->head + silc_buffer_headlen(sb); - sb_new->tail = sb_new->data + silc_buffer_len(sb); + silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb)); return sb_new; } -/****f* silcutil/SilcBufferAPI/silc_buffer_realloc +/****f* silcutil/SilcBufferAPI/silc_buffer_clone * * SYNOPSIS * * static inline - * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize); + * SilcBuffer silc_buffer_clone(SilcBuffer sb); * * DESCRIPTION * - * Reallocates buffer. Old data is saved into the new buffer. The buffer - * is exact clone of the old one except that there is now more space - * at the end of buffer. This always returns the same `sb' unless `sb' - * was NULL. Returns NULL on error. + * Clones SilcBuffer. This generates new SilcBuffer and copies + * everything from the source buffer. The result is exact clone of + * the original buffer. Returns NULL if system is out of memory. * ***/ static inline -SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) +SilcBuffer silc_buffer_clone(SilcBuffer sb) { - SilcUInt32 hlen, dlen; - unsigned char *h; - - if (!sb) - return silc_buffer_alloc(newsize); - - if (silc_unlikely(newsize <= silc_buffer_truelen(sb))) - return sb; + SilcBuffer sb_new; - hlen = silc_buffer_headlen(sb); - dlen = silc_buffer_len(sb); - h = (unsigned char *)silc_realloc(sb->head, newsize); - if (silc_unlikely(!h)) + sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb)); + if (silc_unlikely(!sb_new)) return NULL; - sb->head = h; - sb->data = sb->head + hlen; - sb->tail = sb->data + dlen; - sb->end = sb->head + newsize; + silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb)); + sb_new->data = sb_new->head + silc_buffer_headlen(sb); + sb_new->tail = sb_new->data + silc_buffer_len(sb); - return sb; + return sb_new; } -/****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size +/****f* silcutil/SilcBufferAPI/silc_buffer_sclone * * SYNOPSIS * * static inline - * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize); + * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb); * * DESCRIPTION * - * Same as silc_buffer_realloc but moves moves the tail area - * automatically so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. Returns NULL on error. - * - ***/ - -static inline -SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize) -{ - sb = silc_buffer_realloc(sb, newsize); - if (silc_unlikely(!sb)) - return NULL; - silc_buffer_pull_tail(sb, silc_buffer_taillen(sb)); - return sb; -} - -/****f* silcutil/SilcBufferAPI/silc_buffer_enlarge - * - * SYNOPSIS - * - * static inline - * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size); + * Clones SilcBuffer. This generates new SilcBuffer and copies + * everything from the source buffer. The result is exact clone of + * the original buffer. Returns NULL if system is out of memory. * - * DESCRIPTION + * This routine use SilcStack are memory source. If `stack' is NULL + * reverts back to normal allocating routine. * - * Enlarges the buffer by the amount of `size' if it doesn't have that - * must space in the data area and in the tail area. Moves the tail - * area automatically after enlarging so that the current data area - * is at least the size of `size'. If there is more space than `size' - * in the data area this does not do anything. If there is enough - * space in the tail area this merely moves the tail area to reveal - * the extra space. Returns FALSE on error. + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. * ***/ static inline -SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size) +SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb) { - if (size > silc_buffer_len(sb)) { - if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb)) - if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + - (size - silc_buffer_taillen(sb) - - silc_buffer_len(sb))))) - return FALSE; - silc_buffer_pull_tail(sb, size - silc_buffer_len(sb)); - } - return TRUE; -} + SilcBuffer sb_new; + sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb)); + if (silc_unlikely(!sb_new)) + return NULL; + silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb)); + sb_new->data = sb_new->head + silc_buffer_headlen(sb); + sb_new->tail = sb_new->data + silc_buffer_len(sb); -/* SilcStack aware SilcBuffer routines */ + return sb_new; +} -/****f* silcutil/SilcBufferAPI/silc_buffer_salloc +/****f* silcutil/SilcBufferAPI/silc_buffer_realloc * * SYNOPSIS * * static inline - * SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len); + * SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize); * * DESCRIPTION * - * Allocates new SilcBuffer and returns it. - * - * This routine use SilcStack are memory source. If `stack' is NULL - * reverts back to normal allocating routine. + * Reallocates buffer. Old data is saved into the new buffer. The buffer + * is exact clone of the old one except that there is now more space + * at the end of buffer. This always returns the same `sb' unless `sb' + * was NULL. Returns NULL if system is out of memory. * ***/ static inline -SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len) +SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) { - SilcBuffer sb; + SilcUInt32 hlen, dlen; + unsigned char *h; - if (!stack) - return silc_buffer_alloc(len); + if (!sb) + return silc_buffer_alloc(newsize); - /* Allocate new SilcBuffer */ - sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb)); - if (silc_unlikely(!sb)) - return NULL; + if (silc_unlikely(newsize <= silc_buffer_truelen(sb))) + return sb; - /* Allocate the actual data area */ - sb->head = (unsigned char *)silc_smalloc_ua(stack, len); - if (silc_unlikely(!sb->head)) + hlen = silc_buffer_headlen(sb); + dlen = silc_buffer_len(sb); + h = (unsigned char *)silc_realloc(sb->head, newsize); + if (silc_unlikely(!h)) return NULL; + sb->head = h; + sb->data = sb->head + hlen; + sb->tail = sb->data + dlen; + sb->end = sb->head + newsize; - /* Set pointers to the new buffer */ - sb->data = sb->head; - sb->tail = sb->head; - sb->end = sb->head + len; - - return sb; -} - -/****f* silcutil/SilcBufferAPI/silc_buffer_salloc_size - * - * SYNOPSIS - * - * static inline - * SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len); - * - * DESCRIPTION - * - * Allocates `len' bytes size buffer and moves the tail area automatically - * `len' bytes so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. - * - * This routine use SilcStack are memory source. If `stack' is NULL - * reverts back to normal allocating routine. - * - ***/ - -static inline -SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len) -{ - SilcBuffer sb = silc_buffer_salloc(stack, len); - if (silc_unlikely(!sb)) - return NULL; - silc_buffer_pull_tail(sb, len); return sb; } @@ -1021,11 +1159,14 @@ SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len) * * Reallocates buffer. Old data is saved into the new buffer. The buffer * is exact clone of the old one except that there is now more space - * at the end of buffer. + * at the end of buffer. Returns NULL if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * ***/ static inline @@ -1046,16 +1187,10 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, hlen = silc_buffer_headlen(sb); dlen = silc_buffer_len(sb); - h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb), - sb->head, newsize); - if (!h) { - /* Do slow and stack wasting realloc. The old sb->head is lost and - is freed eventually. */ - h = (unsigned char *)silc_smalloc_ua(stack, newsize); - if (silc_unlikely(!h)) - return NULL; - memcpy(h, sb->head, silc_buffer_truelen(sb)); - } + h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb), + sb->head, newsize); + if (!h) + return NULL; sb->head = h; sb->data = sb->head + hlen; @@ -1065,6 +1200,31 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, return sb; } +/****f* silcutil/SilcBufferAPI/silc_buffer_realloc_size + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize); + * + * DESCRIPTION + * + * Same as silc_buffer_realloc but moves moves the tail area + * automatically so that the buffer is ready to use without calling the + * silc_buffer_pull_tail. Returns NULL if system is out of memory. + * + ***/ + +static inline +SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize) +{ + sb = silc_buffer_realloc(sb, newsize); + if (silc_unlikely(!sb)) + return NULL; + silc_buffer_pull_tail(sb, silc_buffer_taillen(sb)); + return sb; +} + /****f* silcutil/SilcBufferAPI/silc_buffer_srealloc_size * * SYNOPSIS @@ -1077,11 +1237,14 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, * * Same as silc_buffer_srealloc but moves moves the tail area * automatically so that the buffer is ready to use without calling the - * silc_buffer_pull_tail. + * silc_buffer_pull_tail. Returns NULL if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * ***/ static inline @@ -1095,6 +1258,39 @@ SilcBuffer silc_buffer_srealloc_size(SilcStack stack, return sb; } +/****f* silcutil/SilcBufferAPI/silc_buffer_enlarge + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size); + * + * DESCRIPTION + * + * Enlarges the buffer by the amount of `size' if it doesn't have that + * must space in the data area and in the tail area. Moves the tail + * area automatically after enlarging so that the current data area + * is at least the size of `size'. If there is more space than `size' + * in the data area this does not do anything. If there is enough + * space in the tail area this merely moves the tail area to reveal + * the extra space. Returns FALSE if system is out of memory. + * + ***/ + +static inline +SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size) +{ + if (size > silc_buffer_len(sb)) { + if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb)) + if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + + (size - silc_buffer_taillen(sb) - + silc_buffer_len(sb))))) + return FALSE; + silc_buffer_pull_tail(sb, size - silc_buffer_len(sb)); + } + return TRUE; +} + /****f* silcutil/SilcBufferAPI/silc_buffer_senlarge * * SYNOPSIS @@ -1111,11 +1307,14 @@ SilcBuffer silc_buffer_srealloc_size(SilcStack stack, * is at least the size of `size'. If there is more space than `size' * in the data area this does not do anything. If there is enough * space in the tail area this merely moves the tail area to reveal - * the extra space. Returns FALSE on error. + * the extra space. Returns FALSE if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * ***/ static inline @@ -1133,68 +1332,202 @@ SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size) return TRUE; } -/****f* silcutil/SilcBufferAPI/silc_buffer_scopy +/****f* silcutil/SilcBufferAPI/silc_buffer_append * * SYNOPSIS * * static inline - * SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb); + * SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size); * * DESCRIPTION * - * Generates copy of a SilcBuffer. This copies everything inside the - * currently valid data area, nothing more. Use silc_buffer_clone to - * copy entire buffer. + * Appends the current data area by the amount of `size'. The tail area + * of the buffer remains intact and contains the same data than the old + * tail area (the data is copied to the new tail area). After appending + * there is now `size' bytes more free area in the data area. Returns + * FALSE if system is out of memory. * - * This routine use SilcStack are memory source. If `stack' is NULL - * reverts back to normal allocating routine. + * EXAMPLE + * + * Before appending: + * --------------------------------- + * | head | data | tail | + * --------------------------------- + * + * After appending: + * ------------------------------------ + * | head | data | tail | + * ------------------------------------- + * + * silc_buffer_append(sb, 5); * ***/ static inline -SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb) +SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size) { - SilcBuffer sb_new; + if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size))) + return FALSE; - sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb)); - if (silc_unlikely(!sb_new)) - return NULL; - silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb)); + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); - return sb_new; + /* Copy old tail area to new tail area */ + silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb)); + + return TRUE; } -/****f* silcutil/SilcBufferAPI/silc_buffer_sclone +/****f* silcutil/SilcBufferAPI/silc_buffer_append * * SYNOPSIS * * static inline - * SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb); + * SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, + * SilcUInt32 size) * * DESCRIPTION * - * Clones SilcBuffer. This generates new SilcBuffer and copies - * everything from the source buffer. The result is exact clone of - * the original buffer. + * Appends the current data area by the amount of `size'. The tail area + * of the buffer remains intact and contains the same data than the old + * tail area (the data is copied to the new tail area). After appending + * there is now `size' bytes more free area in the data area. Returns + * FALSE if system is out of memory. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. * + * Note that this call consumes the `stack'. The caller should push the + * stack before calling the function and pop it later. + * + * EXAMPLE + * + * Before appending: + * --------------------------------- + * | head | data | tail | + * --------------------------------- + * + * After appending: + * ------------------------------------ + * | head | data | tail | + * ------------------------------------- + * + * silc_buffer_append(sb, 5); + * ***/ static inline -SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb) +SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size) { - SilcBuffer sb_new; + if (silc_unlikely(!silc_buffer_srealloc(stack, sb, + silc_buffer_truelen(sb) + size))) + return FALSE; - sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb)); - if (silc_unlikely(!sb_new)) - return NULL; - silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb)); - sb_new->data = sb_new->head + silc_buffer_headlen(sb); - sb_new->tail = sb_new->data + silc_buffer_len(sb); + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); - return sb_new; + /* Copy old tail area to new tail area */ + silc_buffer_put_tail(sb, sb->tail - size, silc_buffer_taillen(sb)); + + return TRUE; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_strchr + * + * SYNOPSIS + * + * static inline + * unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first); + * + * DESCRIPTION + * + * Returns pointer to the occurence of the character `c' in the buffer + * `sb'. If the `first' is TRUE this finds the first occurene of `c', + * if it is FALSE this finds the last occurence of `c'. If the character + * is found the `sb' data area is moved to that location and its pointer + * is returned. The silc_buffer_data call will return the same pointer. + * Returns NULL if such character could not be located and the buffer + * remains unmodified. + * + * This call is equivalent to strchr(), strrchr(), memchr() and memrchr() + * except it works with SilcBuffer. + * + * NOTES + * + * This searches only the data area of the buffer. Head and tail area + * are not searched. + * + * The `sb' data need not be NULL terminated. + * + ***/ + +static inline +unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first) +{ + int i; + + if (first) { + for (i = 0; i < silc_buffer_len(sb); i++) { + if (sb->data[i] == (unsigned char)c) { + sb->data = &sb->data[i]; + return sb->data; + } + } + } else { + for (i = silc_buffer_len(sb) - 1; 1 >= 0; i--) { + if (sb->data[i] == (unsigned char)c) { + sb->data = &sb->data[i]; + return sb->data; + } + } + } + + return NULL; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_cmp + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2) + * + * DESCRIPTION + * + * Compares if the data area of the buffer `sb1' and `sb2' are identical. + * Returns TRUE if they match and FALSE if they differ. + * + ***/ + +static inline +SilcBool silc_buffer_equal(SilcBuffer sb1, SilcBuffer sb2) +{ + if (silc_buffer_len(sb1) != silc_buffer_len(sb2)) + return FALSE; + return memcmp(sb1->data, sb2->data, silc_buffer_len(sb1)) == 0; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_printf + * + * SYNOPSIS + * + * static inline + * void silc_buffer_printf(SilcBuffer sb, SilcBool newline); + * + * DESCRIPTION + * + * Prints the current data area of `sb' into stdout. If `newline' is + * TRUE prints '\n' after the data in the buffer. + * + ***/ + +static inline +void silc_buffer_printf(SilcBuffer sb, SilcBool newline) +{ + silc_file_write(1, silc_buffer_data(sb), silc_buffer_len(sb)); + if (newline) + printf("\n"); + fflush(stdout); } #endif /* SILCBUFFER_H */