Files
libpicoevent/pe_buffer.c
2018-06-05 15:26:14 +02:00

229 lines
5.0 KiB
C

// A ring buffer implementation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "libpicoevent.h"
enum {
NORMAL_STATE,
WRAPPED_STATE,
};
pe_buffer_t * pe_buffer_new(int size) {
pe_buffer_t *b = (pe_buffer_t *) calloc(1, sizeof(pe_buffer_t));
if (!b) {
exit_failure("malloc\n");
}
b->buf_start = malloc(size);
if (!b->buf_start) {
exit_failure("malloc\n");
}
b->count = 0;
b->buf_end = b->buf_start + size;
b->buf_size = size;
b->data_start = b->buf_start;
b->data_end = b->buf_start;
b->state = NORMAL_STATE;
return b;
}
static uint32_t write_normal(pe_buffer_t * self, uint8_t *input, uint32_t count) {
/* Don't write beyond buffer boundary */
if ( self->data_end + count > self->buf_end ) {
count = self->buf_end - self->data_end;
}
memcpy(self->data_end, input, count);
self->data_end += count;
self->count += count;
return count;
}
static uint32_t write_wrapped(pe_buffer_t * self, uint8_t *input, uint32_t count) {
/* Don't write beyond start of data */
if ( self->data_end + count > self->data_start ) {
count = self->data_start - self->data_end;
}
memcpy(self->data_end, input, count);
self->data_end += count;
self->count += count;
return count;
}
static uint32_t read_normal(pe_buffer_t * self, uint8_t *buf, uint32_t count) {
/* Don't read beyond end of data */
if ( self->data_start + count > self->data_end ) {
count = self->data_end - self->data_start;
}
memcpy(buf, self->data_start, count);
self->data_start += count;
self->count -= count;
return count;
}
static uint32_t read_wrapped(pe_buffer_t * self, uint8_t *buf, uint32_t count) {
/* Don't read beyond end of buffer */
if ( self->data_start + count > self->buf_end ) {
count = self->buf_end - self->data_start;
}
memcpy(buf, self->data_start, count);
self->data_start += count;
self->count -= count;
return count;
}
static uint32_t rewind_normal(pe_buffer_t * self, uint32_t count) {
/* Don't rewind beyond start of buffer */
if ( self->data_start - count < self->buf_start ) {
count = self->data_start - self->buf_start;
}
self->data_start -= count;
self->count += count;
return count;
}
static uint32_t rewind_wrapped(pe_buffer_t * self, uint32_t count) {
/* Don't rewind beyond end of data */
if ( self->data_start - count < self->data_end ) {
count = self->data_start - self->data_end;
}
self->data_start -= count;
self->count += count;
return count;
}
uint32_t pe_buffer_write(pe_buffer_t * self, uint8_t *input, uint32_t count) {
uint32_t written = 0;
if (self->count == self->buf_size) {
return 0;
}
if ( self->state == NORMAL_STATE) {
written = write_normal(self, input, count);
if ( written < count && self->count < self->buf_size ) {
/* Wrap the buffer */
self->state = WRAPPED_STATE;
self->data_end = self->buf_start;
written += write_wrapped(self, input + written, count - written);
}
} else if (self->state == WRAPPED_STATE ) {
written = write_wrapped(self, input, count);
assert(written == count || self->count == self->buf_size);
}
return written;
}
uint32_t pe_buffer_read(pe_buffer_t * self, uint8_t *buf, uint32_t count) {
uint32_t read = 0;
if ( count > self->count) {
count = self->count;
}
if ( self->state == NORMAL_STATE ) {
read = read_normal(self, buf, count);
if ( read < count && self->count > 0) {
/* Wrap the buffer */
self->state = WRAPPED_STATE;
self->data_start = self->buf_start;
read += read_wrapped(self, buf + read, count - read);
}
} else if (self->state == WRAPPED_STATE ) {
read = read_wrapped(self, buf, count);
if ( read < count && self->count > 0) {
/* Wrap the buffer */
self->state = NORMAL_STATE;
self->data_start = self->buf_start;
read += read_normal(self, buf + read, count - read);
}
}
return read;
}
uint32_t pe_buffer_rewind(pe_buffer_t * self, uint32_t count) {
uint32_t rewinded = 0;
if(self->count == self->buf_size) {
return 0;
}
if (self->state == NORMAL_STATE) {
rewinded = rewind_normal(self, count);
if ( rewinded < count ) {
/* Wrap the buffer */
self->state = WRAPPED_STATE;
self->data_start = self->buf_end;
rewinded += rewind_wrapped(self, count - rewinded);
}
} else if (self->state == WRAPPED_STATE ) {
rewinded = rewind_wrapped(self, count);
assert(rewinded == count || self->count == self->buf_size);
}
return rewinded;
}
int pe_buffer_dump(pe_buffer_t * self) {
uint32_t i, data_start, data_end;
data_start = self->data_start - self->buf_start;
data_end = self->data_end - self->buf_start;
printf("[BUFFER: count %d\t size %d] \n", self->count, self->buf_size);
printf("[data_start %d\t data_end %d] \n", data_start, data_end);
for (i = 0; i < self->buf_size; i++) {
if ( i % 25 == 0 ) {
printf("\n");
}
if ( i == data_start ) {
printf("[");
}
if ( i == data_end ) {
printf("]");
}
printf("%02x ", self->buf_start[i]);
}
printf("\n\n");
return 0;
}
uint32_t pe_buffer_size(pe_buffer_t * self) {
return self->count;
}