#include "ucx/buffer.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
UcxBuffer *ucx_buffer_new(
void *space,
size_t capacity,
int flags) {
UcxBuffer *buffer = (UcxBuffer*) malloc(
sizeof(UcxBuffer));
if (buffer) {
buffer->flags = flags;
if (!space) {
buffer->space = (
char*)malloc(capacity);
if (!buffer->space) {
free(buffer);
return NULL;
}
memset(buffer->space,
0, capacity);
buffer->flags |=
UCX_BUFFER_AUTOFREE;
}
else {
buffer->space = (
char*)space;
}
buffer->capacity = capacity;
buffer->size =
0;
buffer->pos =
0;
}
return buffer;
}
void ucx_buffer_free(UcxBuffer *buffer) {
if ((buffer->flags &
UCX_BUFFER_AUTOFREE) ==
UCX_BUFFER_AUTOFREE) {
free(buffer->space);
}
free(buffer);
}
UcxBuffer* ucx_buffer_extract(
UcxBuffer *src,
size_t start,
size_t length,
int flags) {
if (src->size ==
0 || length ==
0 ||
((
size_t)-
1) - start < length || start+length > src->capacity)
{
return NULL;
}
UcxBuffer *dst = (UcxBuffer*) malloc(
sizeof(UcxBuffer));
if (dst) {
dst->space = (
char*)malloc(length);
if (!dst->space) {
free(dst);
return NULL;
}
dst->capacity = length;
dst->size = length;
dst->flags = flags |
UCX_BUFFER_AUTOFREE;
dst->pos =
0;
memcpy(dst->space, src->space+start, length);
}
return dst;
}
int ucx_buffer_seek(UcxBuffer *buffer,
off_t offset,
int whence) {
size_t npos;
switch (whence) {
case SEEK_CUR:
npos = buffer->pos;
break;
case SEEK_END:
npos = buffer->size;
break;
case SEEK_SET:
npos =
0;
break;
default:
return -
1;
}
size_t opos = npos;
npos += offset;
if ((offset >
0 && npos < opos) || (offset <
0 && npos > opos)) {
return -
1;
}
if (npos >= buffer->size) {
return -
1;
}
else {
buffer->pos = npos;
return 0;
}
}
int ucx_buffer_eof(UcxBuffer *buffer) {
return buffer->pos >= buffer->size;
}
int ucx_buffer_extend(UcxBuffer *buffer,
size_t len) {
size_t newcap = buffer->capacity;
if (buffer->capacity + len < buffer->capacity) {
return -
1;
}
while (buffer->capacity + len > newcap) {
newcap <<=
1;
if (newcap < buffer->capacity) {
return -
1;
}
}
char *newspace = (
char*)realloc(buffer->space, newcap);
if (newspace) {
memset(newspace+buffer->size,
0, newcap-buffer->size);
buffer->space = newspace;
buffer->capacity = newcap;
}
else {
return -
1;
}
return 0;
}
size_t ucx_buffer_write(
const void *ptr,
size_t size,
size_t nitems,
UcxBuffer *buffer) {
size_t len;
if(ucx_szmul(size, nitems, &len)) {
return 0;
}
size_t required = buffer->pos + len;
if (buffer->pos > required) {
return 0;
}
if (required > buffer->capacity) {
if ((buffer->flags &
UCX_BUFFER_AUTOEXTEND) ==
UCX_BUFFER_AUTOEXTEND) {
if (ucx_buffer_extend(buffer, required - buffer->capacity)) {
return 0;
}
}
else {
len = buffer->capacity - buffer->pos;
if (size >
1) {
len -= len%size;
}
}
}
if (len ==
0) {
return len;
}
memcpy(buffer->space + buffer->pos, ptr, len);
buffer->pos += len;
if(buffer->pos > buffer->size) {
buffer->size = buffer->pos;
}
return len / size;
}
size_t ucx_buffer_read(
void *ptr,
size_t size,
size_t nitems,
UcxBuffer *buffer) {
size_t len;
if(ucx_szmul(size, nitems, &len)) {
return 0;
}
if (buffer->pos + len > buffer->size) {
len = buffer->size - buffer->pos;
if (size >
1) len -= len%size;
}
if (len <=
0) {
return len;
}
memcpy(ptr, buffer->space + buffer->pos, len);
buffer->pos += len;
return len / size;
}
int ucx_buffer_putc(UcxBuffer *buffer,
int c) {
if(buffer->pos >= buffer->capacity) {
if ((buffer->flags &
UCX_BUFFER_AUTOEXTEND) ==
UCX_BUFFER_AUTOEXTEND) {
if(ucx_buffer_extend(buffer,
1)) {
return EOF;
}
}
else {
return EOF;
}
}
c &= 0xFF;
buffer->space[buffer->pos] = (
char) c;
buffer->pos++;
if(buffer->pos > buffer->size) {
buffer->size = buffer->pos;
}
return c;
}
int ucx_buffer_getc(UcxBuffer *buffer) {
if (ucx_buffer_eof(buffer)) {
return EOF;
}
else {
int c = ((
unsigned char*)buffer->space)[buffer->pos];
buffer->pos++;
return c;
}
}
size_t ucx_buffer_puts(UcxBuffer *buffer,
const char *str) {
return ucx_buffer_write((
const void*)str,
1, strlen(str), buffer);
}
int ucx_buffer_shift_left(UcxBuffer* buffer,
size_t shift) {
if (shift >= buffer->size) {
buffer->pos = buffer->size =
0;
}
else {
memmove(buffer->space, buffer->space + shift, buffer->size - shift);
buffer->size -= shift;
if (buffer->pos >= shift) {
buffer->pos -= shift;
}
else {
buffer->pos =
0;
}
}
return 0;
}
int ucx_buffer_shift_right(UcxBuffer* buffer,
size_t shift) {
size_t req_capacity = buffer->size + shift;
size_t movebytes;
if (buffer->capacity < req_capacity) {
if ((buffer->flags &
UCX_BUFFER_AUTOEXTEND) ==
UCX_BUFFER_AUTOEXTEND) {
if (ucx_buffer_extend(buffer, req_capacity - buffer->capacity)) {
return 1;
}
movebytes = buffer->size;
}
else {
movebytes = buffer->capacity - shift;
}
}
else {
movebytes = buffer->size;
}
memmove(buffer->space + shift, buffer->space, movebytes);
buffer->size = shift+movebytes;
buffer->pos += shift;
if (buffer->pos > buffer->size) {
buffer->pos = buffer->size;
}
return 0;
}
int ucx_buffer_shift(UcxBuffer* buffer,
off_t shift) {
if (shift <
0) {
return ucx_buffer_shift_left(buffer, (
size_t) (-shift));
}
else if (shift >
0) {
return ucx_buffer_shift_right(buffer, (
size_t) shift);
}
else {
return 0;
}
}