aboutsummaryrefslogtreecommitdiff
path: root/src/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/buffer.c')
-rw-r--r--src/buffer.c278
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;
+}
+