shithub: npe

ref: 979ae53cfee913c2d303ab0f95aaa65dace1c7b5
dir: /libnpe_sdl3/iostream.c/

View raw version
#include "_sdl.h"
#include <bio.h>

typedef struct npe_sdl_io npe_sdl_io;

typedef struct {
	const uchar *memdata;
	int memn;
	int mempos;
} Membuf;

static vlong memsize(struct SDL_IOStream *);
static vlong memseek(struct SDL_IOStream *, vlong, int);
static size_t memread(struct SDL_IOStream *, void *, size_t);
static size_t memwrite(struct SDL_IOStream *, const void *, size_t);
static int memclose(struct SDL_IOStream *);

static vlong bsize(struct SDL_IOStream *);
static vlong bseek(struct SDL_IOStream *, vlong, int);
static size_t bread(struct SDL_IOStream *, void *, size_t);
static size_t bwrite(struct SDL_IOStream *, const void *, size_t);
static int bclose(struct SDL_IOStream *);

struct npe_sdl_io {
	union {
		Biobuf;
		Membuf;
	};
};

struct SDL_IOStream {
	vlong (*size)(struct SDL_IOStream *);
	vlong (*seek)(struct SDL_IOStream *, vlong, int);
	size_t (*read)(struct SDL_IOStream *, void *, size_t);
	size_t (*write)(struct SDL_IOStream *, const void *, size_t);
	int (*close)(struct SDL_IOStream *);
	npe_sdl_io *p;
};

SDL_IOStream *
SDL_IOFromFile(const char *file, const char *m)
{
	SDL_IOStream *o;
	int f, mode;

	o = nil;
	mode = -1;
	for(; m != nil && *m; m++){
		if(*m == 'r'){
			if(mode == OWRITE){
badmode:
				werrstr("either read or write supported only");
				return nil;
			}
			mode = OREAD;
		}else if(*m == 'w'){
			if(mode == OREAD)
				goto badmode;
			mode = OWRITE;
		}
	}
	if(mode < 0)
		goto badmode;

	mode |= OCEXEC;
	f = mode & OREAD ? open(file, mode) : create(file, mode, 0644);
	if(f >= 0 &&
	    (o = calloc(1, sizeof(*o)+sizeof(npe_sdl_io))) != nil &&
		Binit((o->p = (void*)(o+1)), f, mode) == 0){
		o->size = bsize;
		o->seek = bseek;
		o->read = bread;
		o->write = bwrite;
		o->close = bclose;
		return o;
	}

	if(f >= 0)
		close(f);
	free(o);

	return nil;
}

SDL_IOStream*
SDL_IOFromConstMem(const void *mem, size_t size)
{
	SDL_IOStream *o;
	Membuf *b;

	o = calloc(1, sizeof(*o)+sizeof(npe_sdl_io));
	if(o == nil)
		return nil;
	o->p = (void*)(o+1);
	b = (void*)o->p;
	b->memdata = mem;
	b->memn = size;
	b->mempos = 0;

	o->size = memsize;
	o->seek = memseek;
	o->read = memread;
	o->write = memwrite;
	o->close = memclose;
	return o;
}

size_t
SDL_ReadIO(SDL_IOStream *o, void *b, size_t n)
{
	return o->read ? o->read(o, b, n) : 0;
}

size_t
SDL_WriteIO(SDL_IOStream *o, const void *b, size_t n)
{
	return o->write ? o->write(o, b, n) : 0;
}

vlong
SDL_SeekIO(SDL_IOStream *o, vlong off, int whence)
{
	return o->seek ? o->seek(o, off, whence) : -1;
}

vlong
SDL_TellIO(SDL_IOStream *o)
{
	return o->seek ? o->seek(o, 0, 1) : -1;
}

vlong
SDL_GetIOSize(SDL_IOStream *o)
{
	return o->size ? o->size(o) : -1;
}

bool
SDL_CloseIO(SDL_IOStream *o)
{
	int r;

	r = o->close ? o->close(o) : 0;
	if(r == 0)
		free(o);
	return r < 0 ? false : true;
}

static vlong
bseek(struct SDL_IOStream *o, vlong off, int whence)
{
	return Bseek(o->p, off, whence);
}

static size_t
bread(struct SDL_IOStream *o, void *b, size_t n)
{
	vlong x;

	if((x = Bread(o->p, b, n)) != n){
		if(x > 0)
			Bseek(o->p, -x, 1);
	}
	return x < 0 ? 0 : x;
}

static size_t
bwrite(struct SDL_IOStream *o, const void *b, size_t n)
{
	vlong x;

	x = Bwrite(o->p, b, n); /* FIXME dunno what to do with partial writes */
	return x < 0 ? 0 : x;
}

static vlong
bsize(struct SDL_IOStream *o)
{
	Dir *s;
	vlong sz;

	sz = -1;
	if((s = dirfstat(Bfildes(o->p))) != nil){
		sz = s->length;
		free(s);
	}

	return sz;
}

static int
bclose(struct SDL_IOStream *o)
{
	return Bterm(o->p);
}

static vlong
memseek(struct SDL_IOStream *o, vlong off, int whence)
{
	Membuf *b;

	b = (Membuf*)o->p;
	switch(whence){
	case 0:
		b->mempos = off;
		break;
	case 1:
		b->mempos += off;
		break;
	case 2:
		b->mempos = b->memn - 1;
		b->mempos -= off;
		break;
	}
	if(b->mempos < 0)
		b->mempos = 0;

	return b->mempos;
}

static size_t
memread(struct SDL_IOStream *o, void *b, size_t n)
{
	Membuf *buf;
	const uchar *dot, *end;

	buf = (Membuf*)o->p;
	end = buf->memdata + buf->memn;
	dot = buf->memdata + buf->mempos;
	assert(dot <= end);
	if(dot + n >= end)
		n = end - dot;
	memmove(b, dot, n);
	buf->mempos += n;
	return n;
}

static size_t
memwrite(struct SDL_IOStream *o, const void *b, size_t n)
{
	Membuf *buf;

	if(n <= 0)
		return 0;
	buf = (Membuf*)o->p;
	memmove(buf->mempos + buf->memdata, b, n);
	buf->mempos += n;
	return n;
}

static vlong
memsize(struct SDL_IOStream *o)
{
	Membuf *b;
	b = (Membuf*)o->p;

	return b->memn;
}

static int
memclose(struct SDL_IOStream *o)
{
	USED(o);
	return 0;
}