forked from Lephenixnoir/hex-editor
108 lines
2.7 KiB
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);
|
|
}
|