diff options
Diffstat (limited to 'sdl2/rwops.ha')
| -rw-r--r-- | sdl2/rwops.ha | 134 | 
1 files changed, 134 insertions, 0 deletions
| diff --git a/sdl2/rwops.ha b/sdl2/rwops.ha new file mode 100644 index 0000000..4605a3a --- /dev/null +++ b/sdl2/rwops.ha @@ -0,0 +1,134 @@ +use io; +use types::c; + +// RWops types +export type rwops_type = enum u32 { +	UNKNOWN = 0, +	WINFILE = 1, +	STDFILE = 2, +	JNIFILE = 3, +	MEMORY = 4, +	MEMORY_RO = 5, +}; + +// The read/write operation structure -- very basic. +export type SDL_RWops = struct { +	sz: *fn(ctx: *SDL_RWops) i64, +	seek: *fn(ctx: *SDL_RWops, offs: i64, whence: int) i64, +	read: *fn(ctx: *SDL_RWops, ptr: *opaque, sz: size, maxnum: size) size, +	write: *fn(ctx: *SDL_RWops, ptr: *const opaque, sz: size, num: size) size, +	close: *fn(ctx: *SDL_RWops) int, + +	type_: rwops_type, +	// XXX: This union is platform-specific +	hidden: union { +		stdio: struct { +			autoclose: bool, +			fp: nullable *opaque, // FILE * +		}, +		mem: struct { +			base: nullable *u8, +			here: nullable *u8, +			stop: nullable *u8, +		}, +		unknown: struct { +			data1: nullable *opaque, +			data2: nullable *opaque, +		}, +	}, +}; + +@symbol("SDL_RWFromFile") fn _rw_from_file( +	file: const *c::char, +	mode: const *c::char, +) *SDL_RWops; + +// Returns the size of an [[SDL_RWops]], or 0 if unknown or error. +// +// See [[stream_from_rw]] for a more idiomatic Hare interface to SDL_RWops. +export @symbol("SDL_RWsize") fn SDL_RWsize(ctx: *SDL_RWops) i64; + +// Closes an [[SDL_RWops]], returning 1 on success or 0 on error. +// +// See [[stream_from_rw]] for a more idiomatic Hare interface to SDL_RWops. +export @symbol("SDL_RWclose") fn SDL_RWclose(ctx: *SDL_RWops) int; + +// TODO: Other RWops wrappers + +// Creates an [[SDL_RWops]] from an [[io::handle]]. Closing the rwops does not close +// the underlying stream. +export fn rw_from_handle(in: io::handle) *SDL_RWops = { +	// TODO: Add stream_from_rw +	let rw = alloc(SDL_RWops { +		sz = &stream_size, +		seek = &stream_seek, +		read = &stream_read, +		write = &stream_write, +		close = &stream_close, +		type_ = rwops_type::UNKNOWN, +		... +	}); +	// Assert that we can cram an io::handle into the SDL_RWops struct +	static assert(size(io::handle) <= size(nullable *u8) * 2); +	let ptr = &rw.hidden.unknown.data1: *io::handle; +	*ptr = in; +	return rw; +}; + +fn stream_size(ctx: *SDL_RWops) i64 = { +	const handle = *(&ctx.hidden.unknown.data1: *io::handle); +	const old = match (io::tell(handle)) { +	case let o: io::off => +		yield o; +	case io::error => +		return -1; +	}; +	io::seek(handle, 0, io::whence::END)!; +	const sz = io::tell(handle)!; +	io::seek(handle, old, io::whence::SET)!; +	return sz; +}; + +fn stream_seek(ctx: *SDL_RWops, offs: i64, whence: int) i64 = { +	const handle = *(&ctx.hidden.unknown.data1: *io::handle); +	// Note: whence values in stdio.h match io::whence +	match (io::seek(handle, offs: io::off, whence: io::whence)) { +	case let o: io::off => +		return o; +	case io::error => +		return -1; +	}; +}; + +fn stream_read(ctx: *SDL_RWops, ptr: *opaque, sz: size, maxnum: size) size = { +	const handle = *(&ctx.hidden.unknown.data1: *io::handle); +	let buf = ptr: *[*]u8; +	match (io::readall(handle, buf[..sz * maxnum])) { +	case let n: size => +		return n / sz; +	case io::EOF => +		return 0; +	case io::error => +		return 0; +	}; +}; + +fn stream_write(ctx: *SDL_RWops, ptr: *const opaque, sz: size, num: size) size = { +	const handle = *(&ctx.hidden.unknown.data1: *io::handle); +	let buf = ptr: *[*]const u8; +	match (io::writeall(handle, buf[..sz * num])) { +	case let n: size => +		return n / sz; +	case io::error => +		return 0; +	}; +}; + +fn stream_close(ctx: *SDL_RWops) int = { +	const handle = *(&ctx.hidden.unknown.data1: *io::handle); +	free(ctx); +	match (io::close(handle)) { +	case void => return 0; +	case io::error => return -1; +	}; +}; | 
