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 pub fn new(stream: T, total_size: u64) -> StreamReader<T> {
62 StreamReader { stream, total_size }
63 }
64}
65
66impl<T> Reader for StreamReader<T>
67where
68 T: io::Read + io::Seek,
69{
70 fn position(&mut self) -> u64 {
71 self.stream.stream_position().unwrap_or(self.total_size)
72 }
73
74 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
75 self.stream.read_exact(buf).map(|_| buf.len())
76 }
77
78 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
79 self.stream.read_exact(buf)
80 }
81
82 fn seek(&mut self, position: u64) -> io::Result<u64> {
83 self.stream.seek(io::SeekFrom::Start(position as _))
84 }
85
86 fn wait_for_file_size(&mut self, target_size: u64) -> ReaderGrowStatus {
87 if self.stream.stream_position().is_err() {
88 ReaderGrowStatus::Timeout
89 } else if target_size > self.total_size {
90 ReaderGrowStatus::SizeBeyondEof
91 } else {
92 ReaderGrowStatus::SizeReached
93 }
94 }
95}
96
97unsafe extern "C" fn get_position(user_data: *mut c_void) -> i64 {
98 let reader = &mut *(user_data as *mut Box<dyn Reader>);
99 reader.position() as _
100}
101
102unsafe extern "C" fn read(data: *mut c_void, size: usize, user_data: *mut c_void) -> c_int {
103 if data.is_null() || size == 0 {
104 return 0;
105 }
106 let reader = &mut *(user_data as *mut Box<dyn Reader>);
107 let buf = slice::from_raw_parts_mut(data as *mut u8, size);
108 if reader.read_exact(buf).is_ok() {
109 0
110 } else {
111 1
112 }
113}
114
115unsafe extern "C" fn seek(position: i64, user_data: *mut c_void) -> c_int {
116 let reader = &mut *(user_data as *mut Box<dyn Reader>);
117 match reader.seek(position as _) {
118 Ok(_) => 0,
119 Err(_) => 1,
120 }
121}
122
123unsafe extern "C" fn wait_for_file_size(
124 target_size: i64,
125 user_data: *mut c_void,
126) -> lh::heif_reader_grow_status {
127 let reader = &mut *(user_data as *mut Box<dyn Reader>);
128 let target_size = target_size as u64;
129 reader.wait_for_file_size(target_size) as _
130}
131
132#[cfg(not(feature = "v1_19"))]
133pub(crate) static HEIF_READER: lh::heif_reader = lh::heif_reader {
134 reader_api_version: 1,
135 get_position: Some(get_position),
136 read: Some(read),
137 seek: Some(seek),
138 wait_for_file_size: Some(wait_for_file_size),
139};
140
141#[cfg(feature = "v1_19")]
142pub(crate) static HEIF_READER: lh::heif_reader = lh::heif_reader {
143 reader_api_version: 1,
144 get_position: Some(get_position),
145 read: Some(read),
146 seek: Some(seek),
147 wait_for_file_size: Some(wait_for_file_size),
148 request_range: None,
149 preload_range_hint: None,
150 release_file_range: None,
151 release_error_msg: None,
152};