buffer.c revision 01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen/*
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen Copyright (c) 2002 Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo 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
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
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.
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen*/
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen/* @UNSAFE: whole file */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen#include "lib.h"
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen#include "buffer.h"
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstruct buffer {
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen pool_t pool;
bad5981f287ff1e4094428e27178062548215a93Timo Sirainen
bad5981f287ff1e4094428e27178062548215a93Timo Sirainen const unsigned char *r_buffer;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen unsigned char *w_buffer;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
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
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;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen unsigned int alloced:1;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen unsigned int readonly:1;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen unsigned int hard:1;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen};
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void buffer_alloc(buffer_t *buf, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(buf->w_buffer == NULL || buf->alloced);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (size == buf->alloc)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(size > buf->alloc);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen buf->w_buffer = p_realloc(buf->pool, buf->w_buffer, buf->alloc, size);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen buf->alloc = size;
01af88dfbb7a022ddb3ab9fb4159f2a4a204ead3Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->r_buffer = buf->w_buffer;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->alloced = TRUE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic int buffer_check_read(const buffer_t *buf,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen size_t *pos, size_t *data_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen size_t used_size, max_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen used_size = I_MIN(buf->used, buf->limit);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (*pos >= used_size - buf->start_pos)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return FALSE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *pos += buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen max_size = used_size - *pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (*data_size > max_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *data_size = max_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return TRUE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic int buffer_check_write(buffer_t *buf, size_t *pos,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen size_t *data_size, int accept_partial)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
156a7c9057782ea8d805c4223082e1dd6041ef21Timo Sirainen size_t max_size, new_size, alloc_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (buf->readonly)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return FALSE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen /* check that we don't overflow size_t */
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (*pos >= (size_t)-1 - buf->start_pos)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return FALSE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *pos += buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen max_size = (size_t)-1 - *pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (*data_size <= max_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen new_size = *pos + *data_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen else {
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (max_size == 0 || !accept_partial)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return FALSE;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen new_size = *pos + max_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *data_size = max_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen }
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* make sure we're within our limits */
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (new_size > buf->limit) {
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (buf->hard) {
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_panic("Buffer full (%"PRIuSIZE_T" > "
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen "%"PRIuSIZE_T")",
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen new_size, buf->limit);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen }
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (!accept_partial || *pos >= buf->limit)
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen return FALSE;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen new_size = buf->limit;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen *data_size = new_size - *pos;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen }
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen /* see if we need to grow the buffer */
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (new_size > buf->alloc) {
156a7c9057782ea8d805c4223082e1dd6041ef21Timo Sirainen alloc_size = nearest_power(new_size);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (alloc_size > buf->limit)
156a7c9057782ea8d805c4223082e1dd6041ef21Timo Sirainen alloc_size = buf->limit;
156a7c9057782ea8d805c4223082e1dd6041ef21Timo Sirainen
156a7c9057782ea8d805c4223082e1dd6041ef21Timo Sirainen if (alloc_size != buf->alloc)
156a7c9057782ea8d805c4223082e1dd6041ef21Timo Sirainen buffer_alloc(buf, alloc_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen }
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (new_size > buf->used)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->used = new_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return TRUE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_static(pool_t pool, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buffer_t *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buf = p_new(pool, buffer_t, 1);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->pool = pool;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->max_alloc = buf->limit = size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buffer_alloc(buf, size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_static_hard(pool_t pool, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buffer_t *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf = buffer_create_static(pool, size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->hard = TRUE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_data(pool_t pool, void *data, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buffer_t *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buf = p_new(pool, buffer_t, 1);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->pool = pool;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf->alloc = buf->max_alloc = buf->limit = size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->r_buffer = buf->w_buffer = data;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_const_data(pool_t pool, const void *data, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buffer_t *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buf = p_new(pool, buffer_t, 1);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->pool = pool;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf->used = buf->alloc = buf->max_alloc = buf->limit = size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->r_buffer = data;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->readonly = TRUE;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenbuffer_t *buffer_create_dynamic(pool_t pool, size_t init_size, size_t max_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buffer_t *buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buf = p_new(pool, buffer_t, 1);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->pool = pool;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->max_alloc = buf->limit = max_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buffer_alloc(buf, init_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid buffer_free(buffer_t *buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (buf->alloced)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen p_free(buf->pool, buf->w_buffer);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen p_free(buf->pool, buf);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid *buffer_free_without_data(buffer_t *buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen void *data;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen data = buf->w_buffer;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen p_free(buf->pool, buf);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return data;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_write(buffer_t *buf, size_t pos,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen const void *data, size_t data_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(buf, &pos, &data_size, TRUE))
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return 0;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen memcpy(buf->w_buffer + pos, data, data_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return data_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_append(buffer_t *buf, const void *data, size_t data_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buffer_write(buf, buf->used - buf->start_pos, data, data_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_append_c(buffer_t *buf, char chr)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen size_t pos, data_size = 1;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen pos = buf->used - buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(buf, &pos, &data_size, TRUE))
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return 0;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (data_size == 1)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->w_buffer[pos] = chr;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return data_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_insert(buffer_t *buf, size_t pos,
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen const void *data, size_t data_size)
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen{
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen size_t move_size, size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
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 if (pos >= move_size)
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen return 0;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen move_size -= pos;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* size == number of bytes we want to modify after pos */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen if (data_size < (size_t)-1 - move_size)
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen size = data_size + move_size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen else
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen size = (size_t)-1;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen if (!buffer_check_write(buf, &pos, &size, TRUE))
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen return 0;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen i_assert(size >= move_size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen size -= move_size;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen /* size == number of bytes we actually inserted. data_size usually. */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen memmove(buf->w_buffer + pos + size, buf->w_buffer + pos, move_size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen memcpy(buf->w_buffer + pos, data, size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen return size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen}
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_delete(buffer_t *buf, size_t pos, size_t size)
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen{
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen size_t end_size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen if (buf->readonly)
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen return 0;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen end_size = I_MIN(buf->used, buf->limit) - buf->start_pos;
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen if (pos >= end_size)
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen return 0;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen end_size -= pos;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen if (size < end_size) {
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete from between */
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen end_size -= size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen memmove(buf->w_buffer + buf->start_pos + pos,
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf->w_buffer + buf->start_pos + pos + size, end_size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen } else {
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen /* delete the rest of the buffer */
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen size = end_size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen end_size = 0;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen }
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen buffer_set_used_size(buf, pos + end_size);
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen return size;
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen}
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen
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{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_read(src, &src_pos, &copy_size))
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return 0;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(dest, &dest_pos, &copy_size, TRUE))
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return 0;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (src == dest) {
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen memmove(dest->w_buffer + dest_pos,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen src->r_buffer + src_pos, copy_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen } else {
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen memcpy(dest->w_buffer + dest_pos,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen src->r_buffer + src_pos, copy_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen }
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return copy_size;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_append_buf(buffer_t *dest, const buffer_t *src,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen size_t src_pos, size_t copy_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buffer_copy(dest, dest->used - dest->start_pos,
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen src, src_pos, copy_size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid *buffer_get_space(buffer_t *buf, size_t pos, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (!buffer_check_write(buf, &pos, &size, FALSE))
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen return NULL;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf->w_buffer + pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid *buffer_append_space(buffer_t *buf, size_t size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buffer_get_space(buf, buf->used - buf->start_pos, size);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenconst void *buffer_get_data(const buffer_t *buf, size_t *used_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (used_size != NULL)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *used_size = I_MIN(buf->used, buf->limit) - buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf->r_buffer + buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid *buffer_get_modifyable_data(const buffer_t *buf, size_t *used_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (used_size != NULL)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen *used_size = I_MIN(buf->used, buf->limit) - buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf->w_buffer + buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid buffer_set_used_size(buffer_t *buf, size_t used_size)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen i_assert(used_size <= I_MIN(buf->alloc, buf->limit) - buf->start_pos);
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->used = used_size + buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_get_used_size(const buffer_t *buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return I_MIN(buf->used, buf->limit) - buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_set_start_pos(buffer_t *buf, size_t abs_pos)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen size_t old = buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen i_assert(abs_pos <= I_MIN(buf->used, buf->limit));
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->start_pos = abs_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return old;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_get_start_pos(const buffer_t *buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_set_limit(buffer_t *buf, size_t limit)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen size_t old = buf->limit;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen if (limit > (size_t)-1 - buf->start_pos)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen limit = (size_t)-1;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen else
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen limit += buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen buf->limit = I_MIN(limit, buf->max_alloc);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen return old - buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_get_limit(const buffer_t *buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf->limit - buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainensize_t buffer_get_size(const buffer_t *buf)
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen{
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen return buf->alloc - buf->start_pos;
def516ea503a60f20d510c14d5070b7ff5bbddf4Timo Sirainen}
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen#ifdef BUFFER_TEST
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen/* gcc buffer.c -o testbuffer liblib.a -Wall -DHAVE_CONFIG_H -DBUFFER_TEST -g */
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainenint main(void)
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buffer_t *buf;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen char data[12], *bufdata;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen size_t bufsize;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen lib_init();
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen memset(data, '!', sizeof(data));
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen bufdata = data + 1;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen bufsize = sizeof(data)-2;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
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(buf->used == 10);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_write(buf, 6, "12345", 5) == 4);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buf->used == 10);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
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 i_assert(buffer_append(buf, "1", 1) == 0);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buf->used == 10);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen buf = buffer_create_data(system_pool, bufdata, bufsize);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_append(buf, "12345", 5) == 5);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buf->used == 5);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_append(buf, "123456", 6) == 5);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buf->used == 10);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen buf = buffer_create_data(system_pool, data, sizeof(data));
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen buffer_set_used_size(buf, 1);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen buffer_set_start_pos(buf, 1);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen buffer_set_limit(buf, sizeof(data)-2);
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(buf->used == 11);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(memcmp(buf->r_buffer, "!1212345345", 11) == 0);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_delete(buf, 2, 5) == 5);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(buf->used == 6);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(memcmp(buf->r_buffer, "!12345", 6) == 0);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(buffer_delete(buf, 3, 5) == 2);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(buf->used == 4);
9edba36ef9b2679b0585c345074b1f1d482bfd20Timo Sirainen i_assert(memcmp(buf->r_buffer, "!123", 4) == 0);
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(data[0] == '!');
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen i_assert(data[sizeof(data)-1] == '!');
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen return 0;
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen}
fc7b32b6a2a65d604c8070b9b1a204f25c90b391Timo Sirainen#endif