shithub: npe

ref: 61db9b4fbe5ad66d0600bca8c39171c027ae2ecd
dir: /libnpe_sdl2/rwops.c/

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

struct npe_sdl_rwops {
	Biobuf;
};

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

SDL_RWops *
SDL_RWFromFile(const char *file, const char *m)
{
	SDL_RWops *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;

	if((f = open(file, mode|OCEXEC)) >= 0 &&
	    (o = calloc(1, sizeof(*o)+sizeof(npe_sdl_rwops))) != 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;
}

size_t
SDL_RWread(SDL_RWops *o, void *b, size_t sz, size_t n)
{
	return o->read ? o->read(o, b, sz, n) : 0;
}

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

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

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

vlong
SDL_RWsize(SDL_RWops *o)
{
	return o->size ? o->size(o) : -1;
}

int
SDL_RWclose(SDL_RWops *o)
{
	int r;

	r = o->close ? o->close(o) : 0;
	if(r == 0)
		free(o);

	return r;
}

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

static size_t
bread(struct SDL_RWops *o, void *b, size_t sz, size_t n)
{
	uchar *p;
	size_t i;
	vlong x;

	for(i = 0, p = b; i < n; i++, p += sz){
		if((x = Bread(o->p, p, sz)) != sz){
			if(x > 0)
				Bseek(o->p, -x, 1);
			break;
		}
	}

	return i;
}

static size_t
bwrite(struct SDL_RWops *o, const void *b, size_t sz, size_t n)
{
	const uchar *p;
	size_t i;

	for(i = 0, p = b; i < n; i++, p += sz){
		if(Bwrite(o->p, p, sz) != sz) /* FIXME dunno what to do with partial writes */
			break;
	}

	return i;
}

static vlong
bsize(struct SDL_RWops *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_RWops *o)
{
	return Bterm(o->p);
}