netcdf-c/libcdmr/ast_byteio.c
2011-06-10 18:47:26 +00:00

291 lines
8.0 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "config.h"
#include <ast_runtime.h>
#include <ast_internal.h>
#define DFALTALLOC 1024
/* Should be exactly eight characters long */
static const char BYTEIO_UIDSTRING[8] = "byteio ";
static uint64_t BYTEIO_UID = 0;
/**************************************************/
/* Byte IO */
/**************************************************/
/* Create a runtime readers and writers backed by a byte buffer */
/* Define the data kept in the stream field of ast_runtime */
struct _ast_bytestream {
bool_t extendible; // 0 => cannot extend
size_t alloc;
size_t pos;
uint8_t* buffer;
struct _ast_stack { /* Only used when reading */
size_t maxpos;
struct _ast_stack* stack;
} stack;
};
static size_t ast_byteio_write(ast_runtime* rt, size_t len, uint8_t* data);
static size_t ast_byteio_read(ast_runtime* rt, size_t len, uint8_t* data);
static int ast_byteio_mark(ast_runtime* rt, size_t count);
static int ast_byteio_unmark(ast_runtime* rt);
static int ast_byteio_reclaim(ast_runtime* rt);
static void* ast_byteio_alloc(ast_runtime* rt, size_t len);
static void ast_byteio_free(ast_runtime* rt, void* mem);
static ast_runtime_ops byteops = {
ast_byteio_write,
ast_byteio_read,
ast_byteio_mark,
ast_byteio_unmark,
ast_byteio_reclaim,
ast_byteio_alloc,
ast_byteio_free
};
static size_t
ast_byteio_write(ast_runtime* rt, size_t len, uint8_t* data)
{
struct _ast_bytestream* stream = NULL;
if(rt == NULL || rt->uid != BYTEIO_UID || rt->mode != AST_WRITE)
return AST_EFAIL;
if(len == 0 || data == NULL) return AST_NOERR;
stream = (struct _ast_bytestream*)rt->stream;
while(stream->pos+len >= stream->alloc) {
if(stream->extendible) {
char* newbuffer = NULL;
size_t delta = DFALTALLOC;
if(stream->buffer == NULL) {
stream->pos = 0;
stream->alloc += delta;
newbuffer = malloc(stream->alloc);
if(newbuffer == NULL) return AST_ENOMEM;
} else {
stream->alloc += delta;
newbuffer = realloc(stream->buffer,stream->alloc);
}
if(newbuffer == NULL) return AST_ENOMEM;
} else return AST_EFAIL; /* Cannot extend */
} /*while*/
memcpy(stream->buffer+stream->pos,(void*)data,len);
stream->pos += len;
return len;
}
static size_t
ast_byteio_read(ast_runtime* rt, size_t len, uint8_t* data)
{
struct _ast_bytestream* stream = NULL;
if(rt == NULL || rt->uid != BYTEIO_UID || rt->mode != AST_READ)
return AST_EFAIL;
if(len == 0 || data == NULL) return AST_NOERR;
stream = (struct _ast_bytestream*)rt->stream;
if(stream->pos+len > stream->stack.maxpos) {
rt->err = AST_EOF;
len = 0;
stream->pos = stream->stack.maxpos;
} else if(stream->pos+len > stream->alloc) {
rt->err = AST_EOF;
len = 0;
stream->pos = stream->alloc;
} else {
memcpy((void*)data,stream->buffer+stream->pos,len);
stream->pos += len;
}
return len;
}
/* limit reads to next n bytes */
static int
ast_byteio_mark(ast_runtime* rt, size_t count)
{
struct _ast_bytestream* stream = NULL;
struct _ast_stack* node = NULL;
if(rt == NULL || rt->uid != BYTEIO_UID || rt->mode != AST_READ)
return AST_EFAIL;
stream = (struct _ast_bytestream*)rt->stream;
node = ast_alloc(rt,sizeof(struct _ast_stack));
if(node == NULL) return AST_ENOMEM;
*node = stream->stack;
stream->stack.stack = node;
stream->stack.maxpos = stream->pos+count;
/* stream maxpos must be <= alloc */
if(stream->stack.maxpos > stream->alloc)
assert(0);
/* stream->stack.maxpos = stream->alloc; */
return AST_NOERR;
}
/* Pop out of the current mark */
static int
ast_byteio_unmark(ast_runtime* rt)
{
struct _ast_bytestream* stream = NULL;
struct _ast_stack* node = NULL;
if(rt == NULL || rt->uid != BYTEIO_UID || rt->mode != AST_READ)
return AST_EFAIL;
stream = (struct _ast_bytestream*)rt->stream;
node = stream->stack.stack;
stream->stack.maxpos = node->maxpos;
if(stream->stack.maxpos > stream->alloc)
assert(0);
stream->stack.stack = node->stack;
ast_free(rt,node);
return AST_NOERR;
}
static int
ast_byteio_reclaim(ast_runtime* rt)
{
struct _ast_bytestream* stream = NULL;
struct _ast_stack* curr = NULL;
if(rt == NULL) return AST_NOERR;
if(rt->uid != BYTEIO_UID) return AST_EFAIL;
stream = (struct _ast_bytestream*)rt->stream;
if(stream->extendible && stream->buffer != NULL) free(stream->buffer);
curr = stream->stack.stack;
while(curr != NULL) {
struct _ast_stack* next = stream->stack.stack;
ast_free(rt,curr);
curr = next;
}
free(rt);
return AST_NOERR;
}
/* Copy out the current position from a byteio runtime */
ast_err
ast_byteio_count(ast_runtime* rt, size_t* countp)
{
struct _ast_bytestream* stream = NULL;
if(rt == NULL || rt->uid != BYTEIO_UID)
return AST_EFAIL;
stream = (struct _ast_bytestream*)rt->stream;
if(countp) *countp = stream->pos;
return AST_NOERR;
}
/* Copy out a pointer to the buffer from a byteio runtime */
ast_err
ast_byteio_content(ast_runtime* rt, bytes_t* result)
{
bytes_t content;
struct _ast_bytestream* stream = NULL;
if(result == NULL) return AST_NOERR;
if(rt == NULL || rt->uid != BYTEIO_UID)
return AST_EFAIL;
stream = (struct _ast_bytestream*)rt->stream;
content.nbytes = stream->pos;
content.bytes = stream->buffer;
if(result) *result = content;
return AST_NOERR;
}
ast_err
ast_byteio_reset(ast_runtime* rt)
{
struct _ast_bytestream* stream = NULL;
if(rt == NULL || rt->uid != BYTEIO_UID)
return AST_EFAIL;
stream = (struct _ast_bytestream*)rt->stream;
stream->alloc = 0;
stream->pos = 0;
stream->buffer = NULL;
return AST_NOERR;
}
unsigned char*
xbytes(ast_runtime* rt)
{
bytes_t content;
ast_err err = ast_byteio_content(rt,&content);
if(err != AST_NOERR) return NULL;
return content.bytes;
}
size_t
xpos(ast_runtime* rt)
{
bytes_t content;
ast_err err = ast_byteio_content(rt,&content);
if(err != AST_NOERR) return 0;
return content.nbytes;
}
int
ast_byteio_new(ast_iomode mode, void* buf, size_t len, ast_runtime** rtp)
{
int status = AST_NOERR;
ast_runtime* rt = NULL;
struct _ast_bytestream* stream = NULL;
if(BYTEIO_UID == 0)
BYTEIO_UID = ast_create_unique_id(BYTEIO_UIDSTRING);
rt = malloc(sizeof(ast_runtime));
if(rt == NULL) {status = AST_ENOMEM; goto fail;}
memset(rt,0,sizeof(ast_runtime));
stream = malloc(sizeof(struct _ast_bytestream));
if(stream == NULL) {status = AST_ENOMEM; goto fail;}
memset(stream,0,sizeof(struct _ast_bytestream));
rt->stream = (void*)stream;
rt->ops = &byteops;
rt->uid = BYTEIO_UID;
rt->mode = mode;
if(mode == AST_READ) {
if(buf == NULL || len == 0) {status = AST_EFAIL; goto fail;}
stream->extendible = 0;
stream->alloc = len;
stream->pos = 0;
stream->buffer = buf;
stream->stack.maxpos = stream->alloc;
} else if(mode == AST_WRITE) {
if(buf == NULL) {
stream->extendible = 1;
/* Use default initial length */
len = DFALTALLOC;
buf = malloc(len);
if(buf == NULL) {status = AST_ENOMEM; goto fail;}
} else {
stream->extendible = 0;
}
stream->alloc = len;
stream->pos = 0;
stream->buffer = buf;
} else {status = AST_EFAIL; goto fail;}
if(rtp) *rtp = rt;
return AST_NOERR;
fail:
if(rt != NULL) free(rt);
if(stream != NULL) free(stream);
if(stream->buffer != buf && mode == AST_WRITE) free(stream->buffer);
return status;
}
/* Wrap calloc and free */
static void*
ast_byteio_alloc(ast_runtime* rt, size_t len)
{
if(len == 0) return NULL;
return calloc(1,len);
}
static void
ast_byteio_free(ast_runtime* rt, void* mem)
{
if(mem != NULL)
free(mem);
}