diff options
Diffstat (limited to 'src/buffer.c')
| -rw-r--r-- | src/buffer.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..c66c6ae --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,278 @@ +#include <bh/internal/buffer.h> +#include <stdlib.h> +#include <string.h> + +static const bh_io_table_t bh_buffer_table = { + (int (*)(struct bh_io_s *, int)) bh_buffer_open_base, + (void (*)(struct bh_io_s *)) bh_buffer_close_base, + (int (*)(struct bh_io_s *)) bh_buffer_is_open_base, + (size_t (*)(struct bh_io_s *, char *, size_t)) bh_buffer_read_base, + (size_t (*)(struct bh_io_s *, const char *, size_t)) bh_buffer_write_base, + (void (*)(struct bh_io_s *)) bh_buffer_flush_base, + (int (*)(struct bh_io_s *, bh_off_t, int)) bh_buffer_seek_base, + (bh_off_t (*)(struct bh_io_s *)) bh_buffer_size_base, + (bh_off_t (*)(struct bh_io_s *)) bh_buffer_tell_base, + (bh_off_t (*)(struct bh_io_s *)) bh_buffer_available_base, + (void (*)(struct bh_io_s *)) bh_buffer_clear_base, + (void (*)(struct bh_io_s *)) bh_buffer_destroy +}; + +bh_buffer_t *bh_buffer_new(void) +{ + bh_buffer_t *result; + + /* Allocate and initialize buffer structure */ + result = malloc(sizeof(*result)); + if (result && bh_buffer_init(result)) + { + /* Something went wrong - free allocated memory */ + free(result); + result = NULL; + } + + return result; +} + +void bh_buffer_free(bh_buffer_t *buffer) +{ + bh_buffer_destroy(buffer); + free(buffer); +} + +int bh_buffer_init(bh_buffer_t *buffer) +{ + bh_io_init(&buffer->base, &bh_buffer_table); + + buffer->data = NULL; + buffer->capacity = 0; + buffer->size = 0; + buffer->at = 0; + buffer->mode = 0; + + return BH_OK; +} + +void bh_buffer_destroy(bh_buffer_t *buffer) +{ + bh_buffer_close(buffer); + if (buffer->data) + free(buffer->data); +} + +const char *bh_buffer_data(bh_buffer_t *buffer) +{ + return buffer->data; +} + +void bh_buffer_set_data(bh_buffer_t *buffer, + const char *data, + size_t size) +{ + buffer->size = 0; + bh_buffer_write_base(buffer, data, size); +} + +size_t bh_buffer_capacity(bh_buffer_t *buffer) +{ + return buffer->capacity; +} + +int bh_buffer_reserve(bh_buffer_t *buffer, + size_t size) +{ + char *data = NULL; + + /* New capacity can't be less then current buffer size */ + if (size < buffer->size) + size = buffer->size; + + /* Prevent same size reallocation */ + if (buffer->capacity == size) + return BH_OK; + + /* Allocate new memory for the buffer */ + if (size) + { + data = malloc(size); + if (!data) + return BH_OOM; + + /* Copy data */ + if (buffer->size) + memmove(data, buffer->data, buffer->size); + } + + /* Free previosly allocated memory */ + if (buffer->data) + free(buffer->data); + + /* Update buffer fields */ + buffer->data = data; + buffer->capacity = size; + + return BH_OK; +} + +int bh_buffer_open_base(bh_buffer_t *buffer, + int mode) +{ + /* Check if buffer is already open */ + if (buffer->mode != 0) + return BH_OK; + + /* Update buffer mode field */ + buffer->mode = mode; + + /* Determine open mode */ + switch (mode & BH_IO_MASK) + { + case BH_IO_OPEN: + case BH_IO_CREATE: + case BH_IO_APPEND: + break; + + case BH_IO_TRUNCATE: + buffer->size = 0; + break; + + default: + return BH_NO_IMPL; + } + + return BH_OK; +} + +void bh_buffer_close_base(bh_buffer_t *buffer) +{ + buffer->mode = 0; +} + +int bh_buffer_is_open_base(bh_buffer_t *buffer) +{ + return buffer->mode != 0; +} + +size_t bh_buffer_read_base(bh_buffer_t *buffer, + char *data, + size_t size) +{ + /* Check if buffer openned in read mode */ + if (!(buffer->mode & BH_IO_READ)) + { + buffer->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Calculate maximum available size for reading */ + if (size > buffer->size - buffer->at) + size = buffer->size - buffer->at; + + /* Perform reading */ + if (size) + { + memmove(data, buffer->data + buffer->at, size); + buffer->at += size; + } + + /* Check for end of file */ + if (!size) + buffer->base.flags |= BH_IO_EOF; + else + buffer->base.flags &= ~BH_IO_EOF; + + return size; +} + +size_t bh_buffer_write_base(bh_buffer_t *buffer, + const char *data, + size_t size) +{ + size_t capacity = 0; + + /* Check if buffer is openned in write mode */ + if (!(buffer->mode & BH_IO_WRITE)) + { + buffer->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Adjust at position */ + if ((buffer->mode & BH_IO_MASK) == BH_IO_APPEND) + buffer->at = buffer->size; + + /* Calculate required capacity and check for overflow */ + capacity = buffer->at + size; + if (capacity < size) + { + buffer->base.flags |= BH_IO_ERROR; + return 0; + } + + /* Try to grow buffer */ + if (buffer->capacity < capacity) + bh_buffer_reserve(buffer, capacity); + + /* Calculate maximum write size */ + if (size > buffer->capacity - buffer->at) + size = buffer->capacity - buffer->at; + + /* Perform writing */ + if (size) + { + memmove(buffer->data + buffer->at, data, size); + buffer->at += size; + buffer->size += size; + } + + /* Check for end of file */ + if (!size) + buffer->base.flags |= BH_IO_EOF; + else + buffer->base.flags &= ~BH_IO_EOF; + + return size; +} + +void bh_buffer_flush_base(bh_buffer_t *buffer) +{ + (void)buffer; +} + +int bh_buffer_seek_base(bh_buffer_t *buffer, + bh_off_t pos, + int dir) +{ + switch (dir) + { + case BH_IO_SET: buffer->at = pos; break; + case BH_IO_CURRENT: buffer->at += pos; break; + case BH_IO_END: buffer->at = buffer->size - pos; break; + default: return BH_NO_IMPL; + } + + if (buffer->at > buffer->size) + buffer->at = buffer->size; + + return BH_OK; +} + +bh_off_t bh_buffer_size_base(bh_buffer_t *buffer) +{ + return buffer->size; +} + +bh_off_t bh_buffer_tell_base(bh_buffer_t *buffer) +{ + return buffer->at; +} + +bh_off_t bh_buffer_available_base(bh_buffer_t *buffer) +{ + return buffer->size - buffer->at; +} + +void bh_buffer_clear_base(bh_buffer_t *buffer) +{ + buffer->base.flags &= ~BH_IO_ERROR; +} + |
