buffer.c revision 01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen Copyright (c) 2002 Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen Permission is hereby granted, free of charge, to any person obtaining
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen a copy of this software and associated documentation files (the
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen "Software"), to deal in the Software without restriction, including
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen without limitation the rights to use, copy, modify, merge, publish,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen distribute, sublicense, and/or sell copies of the Software, and to
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen permit persons to whom the Software is furnished to do so, subject to
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen the following conditions:
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen The above copyright notice and this permission notice shall be
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen included in all copies or substantial portions of the Software.
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen/* @UNSAFE: whole file */
bad5981f287ff1e4094428e27178062548215a93Timo Sirainen const unsigned char *r_buffer;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen unsigned char *w_buffer;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* buffer_set_start_pos() modifies start_pos, but internally we deal
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen only with absolute positions. buffer_check_read|write modifies
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen given position to absolute one.
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen start_pos <= used <= alloc <= max_alloc.
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen start_pos <= limit <= max_alloc */
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen size_t start_pos, used, alloc, max_alloc, limit;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void buffer_alloc(buffer_t *buf, size_t size)
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(buf->w_buffer == NULL || buf->alloced);
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, size);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic int buffer_check_read(const buffer_t *buf,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic int buffer_check_write(buffer_t *buf, size_t *pos,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen /* check that we don't overflow size_t */
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* make sure we're within our limits */
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen /* see if we need to grow the buffer */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_static(pool_t pool, size_t size)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_static_hard(pool_t pool, size_t size)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_data(pool_t pool, void *data, size_t size)
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf->alloc = buf->max_alloc = buf->limit = size;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_const_data(pool_t pool, const void *data, size_t size)
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf->used = buf->alloc = buf->max_alloc = buf->limit = size;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_dynamic(pool_t pool, size_t init_size, size_t max_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(buf, &pos, &data_size, TRUE))
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_append(buffer_t *buf, const void *data, size_t data_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buffer_write(buf, buf->used - buf->start_pos, data, data_size);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_append_c(buffer_t *buf, char chr)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(buf, &pos, &data_size, TRUE))
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_insert(buffer_t *buf, size_t pos,
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* move_size == number of bytes we have to move forward to make space */
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen move_size = I_MIN(buf->used, buf->limit) - buf->start_pos;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* size == number of bytes we want to modify after pos */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen if (!buffer_check_write(buf, &pos, &size, TRUE))
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* size == number of bytes we actually inserted. data_size usually. */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen memmove(buf->w_buffer + pos + size, buf->w_buffer + pos, move_size);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_delete(buffer_t *buf, size_t pos, size_t size)
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen end_size = I_MIN(buf->used, buf->limit) - buf->start_pos;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete from between */
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf->w_buffer + buf->start_pos + pos + size, end_size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete the rest of the buffer */
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_copy(buffer_t *dest, size_t dest_pos,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen const buffer_t *src, size_t src_pos, size_t copy_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_read(src, &src_pos, ©_size))
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(dest, &dest_pos, ©_size, TRUE))
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_append_buf(buffer_t *dest, const buffer_t *src,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buffer_copy(dest, dest->used - dest->start_pos,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid *buffer_get_space(buffer_t *buf, size_t pos, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(buf, &pos, &size, FALSE))
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid *buffer_append_space(buffer_t *buf, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buffer_get_space(buf, buf->used - buf->start_pos, size);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenconst void *buffer_get_data(const buffer_t *buf, size_t *used_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *used_size = I_MIN(buf->used, buf->limit) - buf->start_pos;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid *buffer_get_modifyable_data(const buffer_t *buf, size_t *used_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *used_size = I_MIN(buf->used, buf->limit) - buf->start_pos;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid buffer_set_used_size(buffer_t *buf, size_t used_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen i_assert(used_size <= I_MIN(buf->alloc, buf->limit) - buf->start_pos);
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_get_used_size(const buffer_t *buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return I_MIN(buf->used, buf->limit) - buf->start_pos;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_set_start_pos(buffer_t *buf, size_t abs_pos)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen i_assert(abs_pos <= I_MIN(buf->used, buf->limit));
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_get_start_pos(const buffer_t *buf)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_set_limit(buffer_t *buf, size_t limit)
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen/* gcc buffer.c -o testbuffer liblib.a -Wall -DHAVE_CONFIG_H -DBUFFER_TEST -g */
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf = buffer_create_data(system_pool, bufdata, bufsize);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_write(buf, 5, "12345", 5) == 5);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_write(buf, 6, "12345", 5) == 4);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf = buffer_create_data(system_pool, bufdata, bufsize);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_write(buf, 0, "1234567890", 10) == 10);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_write(buf, 0, "12345678901", 11) == 10);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf = buffer_create_data(system_pool, bufdata, bufsize);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_append(buf, "12345", 5) == 5);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_append(buf, "123456", 6) == 5);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen buf = buffer_create_data(system_pool, data, sizeof(data));
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_append(buf, "12345", 5) == 5);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_insert(buf, 2, "123456", 6) == 5);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(memcmp(buf->r_buffer, "!1212345345", 11) == 0);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(memcmp(buf->r_buffer, "!12345", 6) == 0);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(memcmp(buf->r_buffer, "!123", 4) == 0);