1use std::{
5 collections::HashMap,
6 ffi::{OsStr, OsString},
7 io::{BufRead, BufReader, Read, Seek},
8 sync::RwLock,
9};
10
11use crate::{ImageDecoder, ImageResult};
12
13pub(crate) trait ReadSeek: Read + Seek {}
14impl<T: Read + Seek> ReadSeek for T {}
15
16pub(crate) static DECODING_HOOKS: RwLock<Option<HashMap<OsString, DecodingHook>>> =
17 RwLock::new(None);
18
19pub(crate) type DetectionHook = (&'static [u8], &'static [u8], OsString);
20pub(crate) static GUESS_FORMAT_HOOKS: RwLock<Vec<DetectionHook>> = RwLock::new(Vec::new());
21
22pub struct GenericReader<'a>(pub(crate) BufReader<Box<dyn ReadSeek + 'a>>);
24impl Read for GenericReader<'_> {
25 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
26 self.0.read(buf)
27 }
28 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
29 self.0.read_vectored(bufs)
30 }
31 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
32 self.0.read_to_end(buf)
33 }
34 fn read_to_string(&mut self, buf: &mut String) -> std::io::Result<usize> {
35 self.0.read_to_string(buf)
36 }
37 fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
38 self.0.read_exact(buf)
39 }
40}
41impl BufRead for GenericReader<'_> {
42 fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
43 self.0.fill_buf()
44 }
45 fn consume(&mut self, amt: usize) {
46 self.0.consume(amt)
47 }
48 fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> std::io::Result<usize> {
49 self.0.read_until(byte, buf)
50 }
51 fn read_line(&mut self, buf: &mut String) -> std::io::Result<usize> {
52 self.0.read_line(buf)
53 }
54}
55impl Seek for GenericReader<'_> {
56 fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
57 self.0.seek(pos)
58 }
59 fn rewind(&mut self) -> std::io::Result<()> {
60 self.0.rewind()
61 }
62 fn stream_position(&mut self) -> std::io::Result<u64> {
63 self.0.stream_position()
64 }
65
66 }
68
69pub type DecodingHook =
71 Box<dyn for<'a> Fn(GenericReader<'a>) -> ImageResult<Box<dyn ImageDecoder + 'a>> + Send + Sync>;
72
73pub fn register_decoding_hook(extension: OsString, hook: DecodingHook) -> bool {
75 let mut hooks = DECODING_HOOKS.write().unwrap();
76 if hooks.is_none() {
77 *hooks = Some(HashMap::new());
78 }
79 match hooks.as_mut().unwrap().entry(extension) {
80 std::collections::hash_map::Entry::Vacant(entry) => {
81 entry.insert(hook);
82 true
83 }
84 std::collections::hash_map::Entry::Occupied(_) => false,
85 }
86}
87
88pub fn decoding_hook_registered(extension: &OsStr) -> bool {
90 DECODING_HOOKS
91 .read()
92 .unwrap()
93 .as_ref()
94 .map(|hooks| hooks.contains_key(extension))
95 .unwrap_or(false)
96}
97
98pub fn register_format_detection_hook(
131 extension: OsString,
132 signature: &'static [u8],
133 mask: Option<&'static [u8]>,
134) {
135 GUESS_FORMAT_HOOKS
136 .write()
137 .unwrap()
138 .push((signature, mask.unwrap_or(&[]), extension));
139}