1use std::os::raw::{c_int, c_void};
2use std::{io, slice};
3
4use libheif_sys as lh;
5
6use crate::enums::ReaderGrowStatus;
7
8pub trait Reader {
9 fn position(&mut self) -> u64;
11
12 #[deprecated(since = "2.4.0", note = "use 'read_exact' method instead.")]
15 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;
16
17 fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
19 loop {
20 #[allow(deprecated)]
21 let size = self.read(buf)?;
22 if size == buf.len() {
23 return Ok(());
24 }
25 buf = &mut buf[size..];
26 }
27 }
28
29 fn seek(&mut self, position: u64) -> io::Result<u64>;
31
32 fn wait_for_file_size(&mut self, target_size: u64) -> ReaderGrowStatus;
46}
47
48#[derive(Debug)]
49pub struct StreamReader<T>
50where
51 T: io::Read + io::Seek,
52{
53 stream: T,
54 total_size: u64,
55}
56
57impl<T> StreamReader<T>
58where
59 T: io::Read + io::Seek,
60{
61 #[allow(unsafe_code)]
62 pub fn new(stream: T, total_size: u64) -> StreamReader<T> {
63 StreamReader { stream, total_size }
64 }
65}
66
67impl<T> Reader for StreamReader<T>
68where
69 T: io::Read + io::Seek,
70{
71 #[allow(unsafe_code)]
72 fn position(&mut self) -> u64 {
73 self.stream.stream_position().unwrap_or(self.total_size)
74 }
75
76 #[allow(unsafe_code)]
77 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
78 self.stream.read_exact(buf).map(|_| buf.len())
79 }
80
81 #[allow(unsafe_code)]
82 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
83 self.stream.read_exact(buf)
84 }
85
86 #[allow(unsafe_code)]
87 fn seek(&mut self, position: u64) -> io::Result<u64> {
88 self.stream.seek(io::SeekFrom::Start(position as _))
89 }
90
91 #[allow(unsafe_code)]
92 fn wait_for_file_size(&mut self, target_size: u64) -> ReaderGrowStatus {
93 if self.stream.stream_position().is_err() {
94 ReaderGrowStatus::Timeout
95 } else if target_size > self.total_size {
96 ReaderGrowStatus::SizeBeyondEof
97 } else {
98 ReaderGrowStatus::SizeReached
99 }
100 }
101}
102
103#[allow(unsafe_code)]
104unsafe extern "C" fn get_position(user_data: *mut c_void) -> i64 {
105 let reader = unsafe { &mut *(user_data as *mut Box<dyn Reader>) };
106 reader.position() as _
107}
108
109#[allow(unsafe_code)]
110unsafe extern "C" fn read(data: *mut c_void, size: usize, user_data: *mut c_void) -> c_int {
111 if data.is_null() || size == 0 {
112 return 0;
113 }
114 let reader = unsafe { &mut *(user_data as *mut Box<dyn Reader>) };
115 let buf = unsafe { slice::from_raw_parts_mut(data as *mut u8, size) };
116 if reader.read_exact(buf).is_ok() { 0 } else { 1 }
117}
118
119#[allow(unsafe_code)]
120unsafe extern "C" fn seek(position: i64, user_data: *mut c_void) -> c_int {
121 let reader = unsafe { &mut *(user_data as *mut Box<dyn Reader>) };
122 match reader.seek(position as _) {
123 Ok(_) => 0,
124 Err(_) => 1,
125 }
126}
127
128#[allow(unsafe_code)]
129unsafe extern "C" fn wait_for_file_size(target_size: i64, user_data: *mut c_void) -> lh::heif_reader_grow_status {
130 let reader = unsafe { &mut *(user_data as *mut Box<dyn Reader>) };
131 let target_size = target_size as u64;
132 reader.wait_for_file_size(target_size) as _
133}
134
135#[cfg(not(feature = "v1_19"))]
136pub(crate) static HEIF_READER: lh::heif_reader = lh::heif_reader {
137 reader_api_version: 1,
138 get_position: Some(get_position),
139 read: Some(read),
140 seek: Some(seek),
141 wait_for_file_size: Some(wait_for_file_size),
142};
143
144#[cfg(feature = "v1_19")]
145pub(crate) static HEIF_READER: lh::heif_reader = lh::heif_reader {
146 reader_api_version: 1,
147 get_position: Some(get_position),
148 read: Some(read),
149 seek: Some(seek),
150 wait_for_file_size: Some(wait_for_file_size),
151 request_range: None,
152 preload_range_hint: None,
153 release_file_range: None,
154 release_error_msg: None,
155};