hex-editor/src/buffer.c

108 lines
2.7 KiB
C

#include "buffer.h"
#include <stdlib.h>
#include <string.h>
static inline size_t round_up_to_multiple(size_t n, int multiple)
{
n += multiple - 1;
return n - (n % multiple);
}
buffer_t *buffer_create(size_t initial_size, int block_size)
{
buffer_t *b = calloc(1, sizeof *b);
if(!b || block_size <= 0) goto fail;
/* Round initial size to the next multiple of the block size */
b->data_size = initial_size;
b->mem_size = round_up_to_multiple(initial_size, block_size);
if(b->mem_size == 0)
b->mem_size = block_size;
b->block_size = block_size;
b->mem = malloc(b->mem_size);
if(!b->mem) goto fail;
return b;
fail:
buffer_free(b);
return NULL;
}
bool buffer_resize(buffer_t *b, size_t new_mem_size)
{
/* Determine whether we need to reallocate */
new_mem_size = round_up_to_multiple(new_mem_size, b->block_size);
bool expanding = new_mem_size > b->mem_size;
bool shrinking = new_mem_size + b->block_size < b->mem_size;
if(expanding || shrinking) {
void *new_mem = realloc(b->mem, new_mem_size);
if(!new_mem)
return false;
b->mem = new_mem;
b->mem_size = new_mem_size;
}
return true;
}
bool buffer_write(buffer_t *b, void *data, size_t data_size, off_t offset,
size_t segment_size)
{
if(!b || offset < 0 || offset + segment_size > b->data_size)
return false;
if(data_size == segment_size) {
memcpy(b->mem + offset, data, segment_size);
return true;
}
size_t new_data_size = b->data_size - segment_size + data_size;
buffer_resize(b, new_data_size);
/* Move existing data out of the way, then perform the copy */
memmove(b->mem + offset + data_size, b->mem + offset + segment_size,
b->data_size - (offset + segment_size));
memcpy(b->mem + offset, data, data_size);
b->data_size = new_data_size;
return true;
}
uint8_t *buffer_at(buffer_t *b, off_t offset)
{
if(!b || !b->mem || offset < 0 || offset >= (int)b->data_size)
return NULL;
return b->mem + offset;
}
uint8_t *buffer_insert_at(buffer_t *b, off_t offset)
{
if(!b || offset < 0 || offset > (int)b->data_size)
return NULL;
if(!buffer_resize(b, b->data_size + 1))
return NULL;
uint8_t *byte = b->mem + offset;
memmove(byte+1, byte, b->data_size - offset);
b->data_size += 1;
return byte;
}
bool buffer_remove_at(buffer_t *b, off_t offset)
{
if(!b || offset < 0 || offset >= (int)b->data_size)
return false;
uint8_t *byte = b->mem + offset;
memmove(byte, byte+1, b->data_size - offset - 1);
b->data_size--;
return true;
}
void buffer_free(buffer_t *b)
{
if(b)
free(b->mem);
free(b);
}