From f2fea4c82279c7c975d45ac7d75d33b4d9784462 Mon Sep 17 00:00:00 2001 From: Andelf Date: Mon, 7 Apr 2014 22:48:35 +0800 Subject: [PATCH] Add RWops struct implementation --- src/sdl2/rwops.rs | 137 ++++++++++++++++++++++++++++++++++++++++++-- src/sdl2/surface.rs | 10 ++-- 2 files changed, 136 insertions(+), 11 deletions(-) diff --git a/src/sdl2/rwops.rs b/src/sdl2/rwops.rs index ab4176c6..74d32dbe 100644 --- a/src/sdl2/rwops.rs +++ b/src/sdl2/rwops.rs @@ -1,22 +1,147 @@ +use std::io; +use std::io::IoResult; +use get_error; +use libc::{c_void, c_int}; + #[allow(non_camel_case_types)] pub mod ll { - use libc::{c_uchar, uint8_t, uint32_t, c_schar}; + use libc::{c_uchar, uint32_t, c_schar, FILE, c_void}; + use libc::{c_int, int64_t, size_t}; struct SDL_RWops_Anon { data: [c_uchar, ..24], } + pub type SDL_bool = c_int; + + pub static RW_SEEK_SET: c_int = 0; + pub static RW_SEEK_CUR: c_int = 1; + pub static RW_SEEK_END: c_int = 2; + pub struct SDL_RWops { - pub size: *uint8_t, - pub seek: *uint8_t, - pub read: *uint8_t, - pub write: *uint8_t, - pub close: *uint8_t, + pub size: extern "C" fn(context: *SDL_RWops) -> int64_t, + pub seek: extern "C" fn(context: *SDL_RWops, offset: int64_t, whence: c_int) -> int64_t, + pub read: extern "C" fn(context: *SDL_RWops, ptr: *c_void, + size: size_t, maxnum: size_t) -> size_t, + pub write: extern "C" fn(context: *SDL_RWops, ptr: *c_void, + size: size_t, maxnum: size_t) -> size_t, + pub close: extern "C" fn(context: *SDL_RWops) -> c_int, pub _type: uint32_t, hidden: SDL_RWops_Anon } extern "C" { pub fn SDL_RWFromFile(file: *c_schar, mode: *c_schar) -> *SDL_RWops; + pub fn SDL_RWFromFP(fp: *FILE, autoclose: SDL_bool) -> *SDL_RWops; + pub fn SDL_RWFromMem(mem: *c_void, size: c_int) -> *SDL_RWops; + pub fn SDL_RWFromConstMem(mem: *c_void, size: c_int) -> *SDL_RWops; + + pub fn SDL_AllocRW() -> *SDL_RWops; + pub fn SDL_FreeRW(area: *SDL_RWops); + } +} + +#[deriving(Eq)] #[allow(raw_pointer_deriving)] +pub struct RWops { + pub raw: *ll::SDL_RWops, + pub owned: bool +} + +/// A structure that provides an abstract interface to stream I/O. +impl RWops { + pub fn from_file(path: &Path, mode: &str) -> Result<~RWops, ~str> { + let raw = unsafe { + ll::SDL_RWFromFile(path.to_c_str().unwrap(), mode.to_c_str().unwrap()) + }; + if raw.is_null() { Err(get_error()) } + else { Ok(~RWops{raw: raw, owned: true}) } + } + + pub fn from_bytes(buf: &[u8]) -> Result<~RWops, ~str> { + let raw = unsafe { + ll::SDL_RWFromConstMem(buf.as_ptr() as *c_void, buf.len() as c_int) + }; + if raw.is_null() { Err(get_error()) } + else { Ok(~RWops{raw: raw, owned: true}) } + } +} + +impl Drop for RWops { + fn drop(&mut self) { + // TODO: handle close error + unsafe { + ll::SDL_FreeRW(self.raw); + } + } +} + +impl Reader for RWops { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + let out_len = buf.len() as u64; + // FIXME: it's better to use as_mut_ptr(). + // number of objects read, or 0 at error or end of file. + let ret = unsafe { + ((*self.raw).read)(self.raw, buf.as_ptr() as *c_void, 1, out_len) + }; + if ret == 0 { + Err(io::standard_error(io::EndOfFile)) + } else { + Ok(ret as uint) + } + } +} + +impl Writer for RWops { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + let in_len = buf.len() as u64; + let ret = unsafe { + ((*self.raw).write)(self.raw, buf.as_ptr() as *c_void, 1, in_len) + }; + if ret == 0 { + Err(io::standard_error(io::EndOfFile)) + } else if ret != in_len { + // FIXME: what error should we return here? + Err(io::standard_error(io::EndOfFile)) + } else { + Ok(()) + } + } +} + +impl Seek for RWops { + fn tell(&self) -> IoResult { + let ret = unsafe { + ((*self.raw).seek)(self.raw, 0, ll::RW_SEEK_CUR) + }; + if ret == -1 { + Err(io::IoError::last_error()) + } else { + Ok(ret as u64) + } + } + + fn seek(&mut self, pos: i64, style: io::SeekStyle) -> IoResult<()> { + // whence code is different from SeekStyle + let whence = match style { + io::SeekSet => ll::RW_SEEK_SET, + io::SeekEnd => ll::RW_SEEK_END, + io::SeekCur => ll::RW_SEEK_CUR + }; + let ret = unsafe { + ((*self.raw).seek)(self.raw, pos, whence) + }; + if ret == -1 { + Err(io::IoError::last_error()) + } else { + Ok(()) + } + } +} + +impl Container for RWops { + fn len(&self) -> uint { + unsafe { + ((*self.raw).size)(self.raw) as uint + } } } diff --git a/src/sdl2/surface.rs b/src/sdl2/surface.rs index a6bbf9be..4405b1bc 100644 --- a/src/sdl2/surface.rs +++ b/src/sdl2/surface.rs @@ -166,7 +166,7 @@ impl Surface { pub fn from_bmp(path: &Path) -> Result<~Surface, ~str> { let raw = unsafe { - ll::SDL_LoadBMP_RW(rwops::ll::SDL_RWFromFile(path.to_c_str().unwrap(), "rb".to_c_str().unwrap()), 1) + ll::SDL_LoadBMP_RW(rwops::RWops::from_file(path, "rb").unwrap().raw, 0) }; if raw.is_null() { Err(get_error()) } @@ -174,9 +174,9 @@ impl Surface { } pub fn save_bmp(&self, path: &Path) -> bool { - unsafe { - ll::SDL_SaveBMP_RW(self.raw, rwops::ll::SDL_RWFromFile(path.to_c_str().unwrap(), "wb".to_c_str().unwrap()), 1) == 0 - } + unsafe { + ll::SDL_SaveBMP_RW(self.raw, rwops::RWops::from_file(path, "rb").unwrap().raw, 0) == 0 + } } pub fn set_palette(&self, palette: &pixels::Palette) -> bool { @@ -221,7 +221,7 @@ impl Surface { Err(get_error()) } } - + pub fn set_color_mod(&self, color: pixels::Color) -> bool { let (r, g, b) = match color { pixels::RGB(r, g, b) => (r, g, b),