1use crate::get_error;
2use libc::c_void;
3use libc::{c_char, c_int, size_t};
4use std::ffi::CString;
5use std::io;
6use std::marker::PhantomData;
7use std::path::Path;
8
9use crate::sys;
10
11pub struct RWops<'a> {
13 raw: *mut sys::SDL_RWops,
14 _marker: PhantomData<&'a ()>,
15}
16
17impl<'a> RWops<'a> {
18 #[allow(clippy::trivially_copy_pass_by_ref)]
21 pub unsafe fn raw(&self) -> *mut sys::SDL_RWops {
22 self.raw
23 }
24
25 pub unsafe fn from_ll<'b>(raw: *mut sys::SDL_RWops) -> RWops<'b> {
26 RWops {
27 raw,
28 _marker: PhantomData,
29 }
30 }
31
32 #[doc(alias = "SDL_RWFromFile")]
34 pub fn from_file<P: AsRef<Path>>(path: P, mode: &str) -> Result<RWops<'static>, String> {
35 let raw = unsafe {
36 let path_c = CString::new(path.as_ref().to_str().unwrap()).unwrap();
37 let mode_c = CString::new(mode).unwrap();
38 sys::SDL_RWFromFile(
39 path_c.as_ptr() as *const c_char,
40 mode_c.as_ptr() as *const c_char,
41 )
42 };
43
44 if raw.is_null() {
45 Err(get_error())
46 } else {
47 Ok(RWops {
48 raw,
49 _marker: PhantomData,
50 })
51 }
52 }
53
54 #[doc(alias = "SDL_RWFromConstMem")]
58 pub fn from_bytes(buf: &'a [u8]) -> Result<RWops<'a>, String> {
59 let raw =
60 unsafe { sys::SDL_RWFromConstMem(buf.as_ptr() as *const c_void, buf.len() as c_int) };
61
62 if raw.is_null() {
63 Err(get_error())
64 } else {
65 Ok(RWops {
66 raw,
67 _marker: PhantomData,
68 })
69 }
70 }
71
72 pub fn from_read<T>(r: &mut T, buffer: &'a mut Vec<u8>) -> Result<RWops<'a>, String>
77 where
78 T: io::Read + Sized,
79 {
80 match r.read_to_end(buffer) {
81 Ok(_size) => RWops::from_bytes(buffer),
82 Err(ioerror) => {
83 let msg = format!("IO error: {}", ioerror);
84 Err(msg)
85 }
86 }
87 }
88
89 #[doc(alias = "SDL_RWFromMem")]
93 pub fn from_bytes_mut(buf: &'a mut [u8]) -> Result<RWops<'a>, String> {
94 let raw = unsafe { sys::SDL_RWFromMem(buf.as_ptr() as *mut c_void, buf.len() as c_int) };
95
96 if raw.is_null() {
97 Err(get_error())
98 } else {
99 Ok(RWops {
100 raw,
101 _marker: PhantomData,
102 })
103 }
104 }
105
106 pub fn len(&self) -> Option<usize> {
111 let result = unsafe { ((*self.raw).size.unwrap())(self.raw) };
112
113 match result {
114 -1 => None,
115 v => Some(v as usize),
116 }
117 }
118
119 pub fn is_empty(&self) -> bool {
121 match self.len() {
122 Some(s) => s == 0,
123 None => true,
124 }
125 }
126}
127
128impl<'a> Drop for RWops<'a> {
129 fn drop(&mut self) {
130 let ret = unsafe { ((*self.raw).close.unwrap())(self.raw) };
131 if ret != 0 {
132 panic!("{}", get_error());
133 }
134 }
135}
136
137impl<'a> io::Read for RWops<'a> {
138 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
139 let out_len = buf.len() as size_t;
140 let ret = unsafe {
143 ((*self.raw).read.unwrap())(
144 self.raw,
145 buf.as_ptr() as *mut c_void,
146 1,
147 out_len as libc::size_t,
148 )
149 };
150 Ok(ret)
151 }
152}
153
154impl<'a> io::Write for RWops<'a> {
155 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
156 let in_len = buf.len() as size_t;
157 let ret = unsafe {
158 ((*self.raw).write.unwrap())(
159 self.raw,
160 buf.as_ptr() as *const c_void,
161 1,
162 in_len as libc::size_t,
163 )
164 };
165 Ok(ret)
166 }
167
168 fn flush(&mut self) -> io::Result<()> {
169 Ok(())
170 }
171}
172
173impl<'a> io::Seek for RWops<'a> {
174 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
175 let (whence, offset) = match pos {
177 io::SeekFrom::Start(pos) => (sys::RW_SEEK_SET, pos as i64),
178 io::SeekFrom::End(pos) => (sys::RW_SEEK_END, pos),
179 io::SeekFrom::Current(pos) => (sys::RW_SEEK_CUR, pos),
180 };
181 let ret = unsafe { ((*self.raw).seek.unwrap())(self.raw, offset, whence as i32) };
182 if ret == -1 {
183 Err(io::Error::last_os_error())
184 } else {
185 Ok(ret as u64)
186 }
187 }
188}