#include #include #include 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; }