Skip to main content

tiff_reader/
source.rs

1//! Random-access source abstraction used by the TIFF decoder.
2
3use std::fs::File;
4use std::path::Path;
5use std::sync::Arc;
6
7use memmap2::Mmap;
8
9use crate::error::{Error, Result};
10
11/// Random-access byte source for TIFF decoding.
12pub trait TiffSource: Send + Sync {
13    /// Total object length in bytes.
14    fn len(&self) -> u64;
15
16    /// Returns `true` when the source has no bytes.
17    fn is_empty(&self) -> bool {
18        self.len() == 0
19    }
20
21    /// Read exactly `len` bytes starting at `offset`.
22    fn read_exact_at(&self, offset: u64, len: usize) -> Result<Vec<u8>>;
23
24    /// Expose a whole-object slice when the source is fully resident in memory.
25    fn as_slice(&self) -> Option<&[u8]> {
26        None
27    }
28}
29
30/// Shared source handle used by `TiffFile`.
31pub type SharedSource = Arc<dyn TiffSource>;
32
33/// Memory-mapped file source.
34pub struct MmapSource {
35    mmap: Mmap,
36}
37
38impl MmapSource {
39    pub fn open(path: &Path) -> Result<Self> {
40        let file = File::open(path).map_err(|e| Error::Io(e, path.display().to_string()))?;
41        let mmap =
42            unsafe { Mmap::map(&file) }.map_err(|e| Error::Io(e, path.display().to_string()))?;
43        Ok(Self { mmap })
44    }
45}
46
47impl TiffSource for MmapSource {
48    fn len(&self) -> u64 {
49        self.mmap.len() as u64
50    }
51
52    fn read_exact_at(&self, offset: u64, len: usize) -> Result<Vec<u8>> {
53        let start = usize::try_from(offset).map_err(|_| Error::OffsetOutOfBounds {
54            offset,
55            length: len as u64,
56            data_len: self.len(),
57        })?;
58        let end = start.checked_add(len).ok_or(Error::OffsetOutOfBounds {
59            offset,
60            length: len as u64,
61            data_len: self.len(),
62        })?;
63        if end > self.mmap.len() {
64            return Err(Error::OffsetOutOfBounds {
65                offset,
66                length: len as u64,
67                data_len: self.len(),
68            });
69        }
70        Ok(self.mmap[start..end].to_vec())
71    }
72
73    fn as_slice(&self) -> Option<&[u8]> {
74        Some(&self.mmap)
75    }
76}
77
78/// In-memory byte-vector source.
79pub struct BytesSource {
80    bytes: Vec<u8>,
81}
82
83impl BytesSource {
84    pub fn new(bytes: Vec<u8>) -> Self {
85        Self { bytes }
86    }
87}
88
89impl TiffSource for BytesSource {
90    fn len(&self) -> u64 {
91        self.bytes.len() as u64
92    }
93
94    fn read_exact_at(&self, offset: u64, len: usize) -> Result<Vec<u8>> {
95        let start = usize::try_from(offset).map_err(|_| Error::OffsetOutOfBounds {
96            offset,
97            length: len as u64,
98            data_len: self.len(),
99        })?;
100        let end = start.checked_add(len).ok_or(Error::OffsetOutOfBounds {
101            offset,
102            length: len as u64,
103            data_len: self.len(),
104        })?;
105        if end > self.bytes.len() {
106            return Err(Error::OffsetOutOfBounds {
107                offset,
108                length: len as u64,
109                data_len: self.len(),
110            });
111        }
112        Ok(self.bytes[start..end].to_vec())
113    }
114
115    fn as_slice(&self) -> Option<&[u8]> {
116        Some(&self.bytes)
117    }
118}