X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcbuffer.h;h=dc9d405cdb51ea3b0714179ab9261c2b1e16fed6;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=30f11dc344d7c9177988f2d3a9ba79e528abb751;hpb=51558729d89b9f3492b2ca754242ed548a579ca4;p=silc.git diff --git a/lib/silcutil/silcbuffer.h b/lib/silcutil/silcbuffer.h index 30f11dc3..dc9d405c 100644 --- a/lib/silcutil/silcbuffer.h +++ b/lib/silcutil/silcbuffer.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1998 - 2007 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 @@ -135,6 +135,21 @@ typedef struct SilcBufferObject { #define silc_buffer_data(x) (x)->data /***/ +/****f* silcutil/SilcBufferAPI/silc_buffer_tail + * + * NAME + * + * unsigned char *silc_buffer_tail(SilcBuffer sb) + * + * DESCRIPTION + * + * Returns pointer to the tail area of the buffer. + * + * SOURCE + */ +#define silc_buffer_tail(x) (x)->tail +/***/ + /****f* silcutil/SilcBufferAPI/silc_buffer_datalen * * NAME @@ -554,7 +569,7 @@ 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 if the push would lead to - * buffer underflow or would go under the valid data area. + * go beyond the buffer boundaries or current data area. * * EXAMPLE * @@ -582,7 +597,7 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len) SILC_ASSERT((sb->data - len) >= sb->head); #endif /* SILC_DIST_INPLACE */ if (silc_unlikely((sb->data - len) < sb->head)) { - silc_set_errno(SILC_ERR_UNDERFLOW); + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; } @@ -649,7 +664,7 @@ 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 if the push would lead to - * buffer underflow or go under valid tail area. + * go beyond buffer boundaries or current tail area. * * EXAMPLE * @@ -677,7 +692,7 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len) SILC_ASSERT((sb->tail - len) >= sb->data); #endif /* SILC_DIST_INPLACE */ if (silc_unlikely((sb->tail - len) < sb->data)) { - silc_set_errno(SILC_ERR_UNDERFLOW); + silc_set_errno(SILC_ERR_OVERFLOW); return NULL; } @@ -725,6 +740,14 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb, return NULL; } + 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); } @@ -768,6 +791,14 @@ unsigned char *silc_buffer_put(SilcBuffer sb, return NULL; } + 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); } @@ -811,6 +842,14 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb, return NULL; } + 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); } @@ -1092,10 +1131,15 @@ SilcBuffer silc_buffer_sclone(SilcStack stack, 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 + * is exact clone of the old one except that there is now more/less space * at the end of buffer. This always returns the same `sb' unless `sb' * was NULL. Returns NULL if system is out of memory. * + * If the `newsize' is shorter than the current buffer size, the data + * and tail area of the buffer must be set to correct position before + * calling this function so that buffer overflow would not occur when + * the buffer size is reduced. + * ***/ static inline @@ -1107,7 +1151,7 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) if (!sb) return silc_buffer_alloc(newsize); - if (silc_unlikely(newsize <= silc_buffer_truelen(sb))) + if (silc_unlikely(newsize == silc_buffer_truelen(sb))) return sb; hlen = silc_buffer_headlen(sb); @@ -1134,8 +1178,14 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) * 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. Returns NULL if system is out of memory. + * is exact clone of the old one except that there is now more/less space + * at the end of buffer. Returns NULL if system is out of memory. This + * always returns `sb' unless `sb' was NULL. + * + * If the `newsize' is shorter than the current buffer size, the data + * and tail area of the buffer must be set to correct position before + * calling this function so that buffer overflow would not occur when + * the buffer size is reduced. * * This routine use SilcStack are memory source. If `stack' is NULL * reverts back to normal allocating routine. @@ -1158,21 +1208,15 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, if (!sb) return silc_buffer_salloc(stack, newsize); - if (newsize <= silc_buffer_truelen(sb)) + if (newsize == silc_buffer_truelen(sb)) return sb; hlen = silc_buffer_headlen(sb); dlen = silc_buffer_len(sb); h = (unsigned char *)silc_srealloc(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(stack, newsize); - if (silc_unlikely(!h)) - return NULL; - memcpy(h, sb->head, silc_buffer_truelen(sb)); - } + if (!h) + return NULL; sb->head = h; sb->data = sb->head + hlen; @@ -1314,6 +1358,106 @@ SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size) return TRUE; } +/****f* silcutil/SilcBufferAPI/silc_buffer_append + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_append(SilcBuffer sb, SilcUInt32 size); + * + * DESCRIPTION + * + * 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. + * + * EXAMPLE + * + * Before appending: + * --------------------------------- + * | head | data | tail | + * --------------------------------- + * + * After appending: + * ------------------------------------ + * | head | data | tail | + * ------------------------------------- + * + * silc_buffer_append(sb, 5); + * + ***/ + +static inline +SilcBool silc_buffer_append(SilcBuffer sb, SilcUInt32 size) +{ + if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + size))) + return FALSE; + + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); + + /* 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_append + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, + * SilcUInt32 size) + * + * DESCRIPTION + * + * 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 +SilcBool silc_buffer_sappend(SilcStack stack, SilcBuffer sb, SilcUInt32 size) +{ + if (silc_unlikely(!silc_buffer_srealloc(stack, sb, + silc_buffer_truelen(sb) + size))) + return FALSE; + + /* Enlarge data area */ + silc_buffer_pull_tail(sb, size); + + /* 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 @@ -1367,4 +1511,74 @@ unsigned char *silc_buffer_strchr(SilcBuffer sb, int c, SilcBool first) return NULL; } +/****f* silcutil/SilcBufferAPI/silc_buffer_equal + * + * 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_memcmp + * + * SYNOPSIS + * + * static inline + * SilcBool silc_buffer_memcmp(SilcBuffer buffer, + * const unsigned char *data, + * SilcUInt32 data_len) + * + * DESCRIPTION + * + * Compares the data area of the buffer with the `data'. Returns TRUE + * if the data area is identical to `data' or FALSE if they differ. + * + ***/ + +static inline +SilcBool silc_buffer_memcmp(SilcBuffer buffer, const unsigned char *data, + SilcUInt32 data_len) +{ + if (silc_buffer_len(buffer) != data_len) + return FALSE; + return memcmp(buffer->data, data, data_len) == 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 */