1use std::{
4 convert::{TryFrom, TryInto},
5 io::{self, Read, Seek, SeekFrom, Write},
6 os::raw::{c_int, c_void},
7 slice,
8};
9
10type ReadPacketCallback =
11 extern "C" fn(opaque: *mut c_void, buffer: *mut u8, buffer_size: c_int) -> c_int;
12
13type WritePacketCallback =
14 extern "C" fn(opaque: *mut c_void, buffer: *const u8, buffer_size: c_int) -> c_int;
15
16type SeekCallback = extern "C" fn(opaque: *mut c_void, offset: i64, whence: c_int) -> i64;
17
18extern "C" {
19 fn ffw_io_whence_to_seek_mode(whence: c_int) -> c_int;
20
21 fn ffw_io_context_new(
22 buffer_size: c_int,
23 write_flag: c_int,
24 opaque: *mut c_void,
25 read_packet: Option<ReadPacketCallback>,
26 write_packet: Option<WritePacketCallback>,
27 seek: Option<SeekCallback>,
28 ) -> *mut c_void;
29 fn ffw_io_context_free(context: *mut c_void);
30}
31
32#[allow(clippy::upper_case_acronyms)]
34pub(crate) struct IOContext {
35 ptr: *mut c_void,
36}
37
38impl IOContext {
39 pub unsafe fn from_raw_ptr(ptr: *mut c_void) -> Self {
41 IOContext { ptr }
42 }
43
44 pub fn as_mut_ptr(&mut self) -> *mut c_void {
46 self.ptr
47 }
48}
49
50impl Drop for IOContext {
51 fn drop(&mut self) {
52 unsafe { ffw_io_context_free(self.ptr) }
53 }
54}
55
56unsafe impl Send for IOContext {}
57unsafe impl Sync for IOContext {}
58
59fn get_seekable_length<T>(seekable: &mut T) -> Result<u64, std::io::Error>
62where
63 T: Seek,
64{
65 let current_position = seekable.stream_position()?;
66 let end_position = seekable.seek(SeekFrom::End(0))?;
67
68 seekable.seek(SeekFrom::Start(current_position))?;
69
70 Ok(end_position)
71}
72
73extern "C" fn io_seek<T>(opaque: *mut c_void, offset: i64, whence: c_int) -> i64
75where
76 T: Seek,
77{
78 fn inner<U>(input: &mut U, offset: i64, mode: c_int) -> io::Result<i64>
79 where
80 U: Seek,
81 {
82 if mode == 0 {
85 return get_seekable_length(input)?
86 .try_into()
87 .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "out of range"));
88 }
89
90 let pos = match mode {
91 1 => u64::try_from(offset)
93 .map(SeekFrom::Start)
94 .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "invalid offset"))?,
95
96 2 => SeekFrom::Current(offset),
98
99 3 => SeekFrom::End(offset),
101
102 _ => {
103 return Err(io::Error::new(
104 io::ErrorKind::InvalidInput,
105 "invalid whence",
106 ))
107 }
108 };
109
110 input
111 .seek(pos)?
112 .try_into()
113 .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "out of range"))
114 }
115
116 let input_ptr = opaque as *mut T;
117
118 let input = unsafe { &mut *input_ptr };
119
120 let mode = unsafe { ffw_io_whence_to_seek_mode(whence) };
121
122 match inner(input, offset, mode) {
123 Ok(len) => len,
124 Err(err) => err
125 .raw_os_error()
126 .map(|code| unsafe { crate::ffw_error_from_posix(code as _) })
127 .unwrap_or_else(|| unsafe { crate::ffw_error_unknown }) as i64,
128 }
129}
130
131extern "C" fn io_read_packet<T>(opaque: *mut c_void, buffer: *mut u8, buffer_size: c_int) -> c_int
133where
134 T: Read,
135{
136 let input_ptr = opaque as *mut T;
137
138 let input = unsafe { &mut *input_ptr };
139
140 let buffer = unsafe { slice::from_raw_parts_mut(buffer, buffer_size as usize) };
141
142 match input.read(buffer) {
143 Ok(n) => {
144 if n > 0 {
145 n as c_int
146 } else {
147 unsafe { crate::ffw_error_eof }
148 }
149 }
150 Err(err) => {
151 if let Some(code) = err.raw_os_error() {
152 unsafe { crate::ffw_error_from_posix(code as _) }
153 } else if err.kind() == io::ErrorKind::WouldBlock {
154 unsafe { crate::ffw_error_would_block }
155 } else {
156 unsafe { crate::ffw_error_unknown }
157 }
158 }
159 }
160}
161
162extern "C" fn io_write_packet<T>(
164 opaque: *mut c_void,
165 buffer: *const u8,
166 buffer_size: c_int,
167) -> c_int
168where
169 T: Write,
170{
171 let output_ptr = opaque as *mut T;
172
173 let output = unsafe { &mut *output_ptr };
174
175 if !buffer.is_null() && buffer_size > 0 {
176 let buffer = unsafe { slice::from_raw_parts(buffer, buffer_size as usize) };
177
178 match output.write(buffer) {
179 Ok(n) => {
180 if n > 0 {
181 n as c_int
182 } else {
183 unsafe { crate::ffw_error_eof }
184 }
185 }
186 Err(err) => {
187 if let Some(code) = err.raw_os_error() {
188 unsafe { crate::ffw_error_from_posix(code as _) }
189 } else if err.kind() == io::ErrorKind::WouldBlock {
190 unsafe { crate::ffw_error_would_block }
191 } else {
192 unsafe { crate::ffw_error_unknown }
193 }
194 }
195 }
196 } else if let Err(err) = output.flush() {
197 if let Some(code) = err.raw_os_error() {
198 unsafe { crate::ffw_error_from_posix(code) }
199 } else if err.kind() == io::ErrorKind::WouldBlock {
200 unsafe { crate::ffw_error_would_block }
201 } else {
202 unsafe { crate::ffw_error_unknown }
203 }
204 } else {
205 0
206 }
207}
208
209#[allow(clippy::upper_case_acronyms)]
211pub struct IO<T> {
212 io_context: IOContext,
213 stream: Box<T>,
214}
215
216impl<T> IO<T> {
217 fn new(
219 stream: T,
220 read_packet: Option<ReadPacketCallback>,
221 write_packet: Option<WritePacketCallback>,
222 seek: Option<SeekCallback>,
223 ) -> Self {
224 let mut stream = Box::new(stream);
225 let stream_ptr = stream.as_mut() as *mut T;
226 let opaque_ptr = stream_ptr as *mut c_void;
227
228 let write_flag = i32::from(write_packet.is_some());
229
230 let io_context = unsafe {
231 ffw_io_context_new(
232 4096,
233 write_flag,
234 opaque_ptr,
235 read_packet,
236 write_packet,
237 seek,
238 )
239 };
240
241 if io_context.is_null() {
242 panic!("unable to allocate an AVIO context");
243 }
244
245 let io_context = unsafe { IOContext::from_raw_ptr(io_context) };
246
247 Self { io_context, stream }
248 }
249
250 pub(crate) fn io_context_mut(&mut self) -> &mut IOContext {
252 &mut self.io_context
253 }
254
255 pub fn stream(&self) -> &T {
257 self.stream.as_ref()
258 }
259
260 pub fn stream_mut(&mut self) -> &mut T {
262 self.stream.as_mut()
263 }
264
265 pub fn into_stream(self) -> T {
267 *self.stream
268 }
269}
270
271impl<T> IO<T>
272where
273 T: Read,
274{
275 pub fn from_read_stream(stream: T) -> Self {
277 Self::new(stream, Some(io_read_packet::<T>), None, None)
278 }
279}
280
281impl<T> IO<T>
282where
283 T: Read + Seek,
284{
285 pub fn from_seekable_read_stream(stream: T) -> Self {
287 Self::new(stream, Some(io_read_packet::<T>), None, Some(io_seek::<T>))
288 }
289}
290
291impl<T> IO<T>
292where
293 T: Write,
294{
295 pub fn from_write_stream(stream: T) -> Self {
297 Self::new(stream, None, Some(io_write_packet::<T>), None)
298 }
299}
300
301impl<T> IO<T>
302where
303 T: Write + Seek,
304{
305 pub fn from_seekable_write_stream(stream: T) -> Self {
307 Self::new(stream, None, Some(io_write_packet::<T>), Some(io_seek::<T>))
308 }
309}
310
311#[derive(Default)]
314pub struct MemWriter {
315 data: Vec<u8>,
316}
317
318impl MemWriter {
319 pub fn take_data(&mut self) -> Vec<u8> {
321 let res = Vec::from(self.data.as_slice());
322
323 self.data.clear();
324
325 res
326 }
327}
328
329impl Write for MemWriter {
330 fn write(&mut self, buffer: &[u8]) -> Result<usize, io::Error> {
331 self.data.extend_from_slice(buffer);
332
333 Ok(buffer.len())
334 }
335
336 #[inline]
337 fn flush(&mut self) -> Result<(), io::Error> {
338 Ok(())
339 }
340}