aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2021-12-12 13:27:45 +0100
committerDrew DeVault <sir@cmpwn.com>2021-12-12 13:45:18 +0100
commit6843b25b2fd4f8286f46403bfaf519e64b5e676d (patch)
tree6bfe0d0d6024fecf47978e181b442809385b44bd
parentall: add error handling on init (diff)
downloadhare-chip8-6843b25b2fd4f8286f46403bfaf519e64b5e676d.tar.gz
Add rwops io::stream implementation
-rw-r--r--sdl2/rwops.ha128
1 files changed, 128 insertions, 0 deletions
diff --git a/sdl2/rwops.ha b/sdl2/rwops.ha
new file mode 100644
index 0000000..4638c29
--- /dev/null
+++ b/sdl2/rwops.ha
@@ -0,0 +1,128 @@
+use io;
+use strings;
+
+// 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 rwops = struct {
+ sz: *fn(ctx: *rwops) i64,
+ seek: *fn(ctx: *rwops, offs: i64, whence: int) i64,
+ read: *fn(ctx: *rwops, ptr: *void, sz: size, maxnum: size) size,
+ write: *fn(ctx: *rwops, ptr: *void, sz: size, num: size) size,
+ close: *fn(ctx: *rwops) void,
+
+ type_: rwops_type,
+ // XXX: This union is platform-specific
+ hidden: union {
+ stdio: struct {
+ autoclose: bool,
+ fp: nullable *void, // FILE *
+ },
+ mem: struct {
+ base: nullable *u8,
+ here: nullable *u8,
+ stop: nullable *u8,
+ },
+ unknown: struct {
+ data1: nullable *void,
+ data2: nullable *void,
+ },
+ },
+};
+
+@symbol("SDL_RWFromFile") fn _rw_from_file(
+ file: const *char,
+ mode: const *char,
+) *rwops;
+
+// Returns the size of an [[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 rwsize(ctx: *rwops) i64;
+
+// Closes an [[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 rwclose(ctx: *rwops) int;
+
+// TODO: Other RWops wrappers
+
+// Creates an [[rwops]] from an [[io::handle]]. Closing the rwops does not close
+// the underlying stream.
+export fn rw_from_handle(in: io::handle) *rwops = {
+ // TODO: Add stream_from_rw
+ let rw = alloc(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: *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: *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: *rwops, ptr: *void, sz: size, maxnum: size) size = {
+ const handle = *(&ctx.hidden.unknown.data1: *io::handle);
+ let buf = ptr: *[*]u8;
+ match (io::readitems(handle, buf[..sz * maxnum], sz)) {
+ case let n: size =>
+ return n;
+ case io::error =>
+ return 0;
+ };
+};
+
+fn stream_write(ctx: *rwops, ptr: *void, sz: size, num: size) size = {
+ const handle = *(&ctx.hidden.unknown.data1: *io::handle);
+ let buf = ptr: *[*]u8;
+ match (io::writeitems(handle, buf[..sz * num], sz)) {
+ case let n: size =>
+ return n;
+ case io::error =>
+ return 0;
+ };
+};
+
+fn stream_close(ctx: *rwops) void = {
+ const handle = *(&ctx.hidden.unknown.data1: *io::handle);
+ free(ctx);
+};