X-Git-Url: http://git.silcnet.org/gitweb/?p=crypto.git;a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcbuffer.h;h=3a3db7b679ffc7283060054813544fc80e2b69a7;hp=5fb70b84ffafb515387d4d3d82dceeef5c06eb41;hb=38b10925eeea619c2b6fa646892df4416e6dd08f;hpb=d193b3700c5955f07de29336140e9f69961a938a diff --git a/lib/silcutil/silcbuffer.h b/lib/silcutil/silcbuffer.h index 5fb70b84..3a3db7b6 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 @@ -238,7 +238,8 @@ SilcUInt32 silc_buffer_taillen(SilcBuffer x) * * 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. * ***/ @@ -276,7 +277,8 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len) * * DESCRIPTION * - * Allocates new SilcBuffer and returns it. + * 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. @@ -503,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 * @@ -526,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; } @@ -547,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 * @@ -570,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; } @@ -591,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 * @@ -614,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; } @@ -635,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 * @@ -658,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; } @@ -680,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 * @@ -699,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); } @@ -720,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 * @@ -739,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); } @@ -760,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 * @@ -779,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); } @@ -799,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. * ***/ @@ -824,7 +874,7 @@ SilcBuffer silc_buffer_alloc_size(SilcUInt32 len) * * 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. + * 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. @@ -939,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. * ***/ @@ -967,7 +1017,7 @@ SilcBuffer silc_buffer_copy(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. + * 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. @@ -1001,7 +1051,7 @@ SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb) * * 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. + * the original buffer. Returns NULL if system is out of memory. * ***/ @@ -1031,7 +1081,7 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb) * * Clones SilcBuffer. This generates new SilcBuffer and copies * everything from the source buffer. The result is exact clone of - * the original buffer. + * the original 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. @@ -1068,7 +1118,7 @@ SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb) * 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. + * was NULL. Returns NULL if system is out of memory. * ***/ @@ -1109,7 +1159,7 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) * * 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. @@ -1139,14 +1189,8 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, 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; @@ -1167,7 +1211,7 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, * * 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. + * silc_buffer_pull_tail. Returns NULL if system is out of memory. * ***/ @@ -1193,7 +1237,7 @@ SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize) * * 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. @@ -1229,7 +1273,7 @@ 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. * ***/ @@ -1263,7 +1307,7 @@ SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size) * 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. @@ -1288,4 +1332,202 @@ 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 + * + * 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 */