Skip to main content

macho_core/format/io/
reader.rs

1use crate::error::{Error, Result};
2use crate::format::io::endian::Endian;
3
4/// The BinaryReader type.
5pub struct BinaryReader<'data> {
6    data: &'data [u8],
7    endian: Endian,
8    offset: usize,
9}
10
11impl<'data> BinaryReader<'data> {
12    /// Performs new.
13    pub fn new(data: &'data [u8], endian: Endian) -> Self {
14        Self {
15            data,
16            endian,
17            offset: 0,
18        }
19    }
20
21    /// Performs at_offset.
22    pub fn at_offset(data: &'data [u8], endian: Endian, offset: usize) -> Self {
23        Self {
24            data,
25            endian,
26            offset,
27        }
28    }
29
30    /// Performs offset.
31    pub fn offset(&self) -> usize {
32        self.offset
33    }
34
35    /// Performs remaining.
36    pub fn remaining(&self) -> usize {
37        self.data.len().saturating_sub(self.offset)
38    }
39
40    /// Performs len.
41    pub fn len(&self) -> usize {
42        self.data.len()
43    }
44
45    /// Performs is_empty.
46    pub fn is_empty(&self) -> bool {
47        self.data.is_empty()
48    }
49
50    /// Performs endian.
51    pub fn endian(&self) -> Endian {
52        self.endian
53    }
54
55    /// Performs seek.
56    pub fn seek(&mut self, offset: usize) {
57        self.offset = offset;
58    }
59
60    /// Performs skip.
61    pub fn skip(&mut self, n: usize) -> Result<()> {
62        let new_offset = self
63            .offset
64            .checked_add(n)
65            .ok_or_else(|| self.bounds_err(n))?;
66        if new_offset > self.data.len() {
67            return Err(self.bounds_err(n));
68        }
69        self.offset = new_offset;
70        Ok(())
71    }
72
73    /// Performs read_u8.
74    pub fn read_u8(&mut self) -> Result<u8> {
75        if self.offset >= self.data.len() {
76            return Err(self.bounds_err(1));
77        }
78        let val = self.data[self.offset];
79        self.offset += 1;
80        Ok(val)
81    }
82
83    /// Performs read_u16.
84    pub fn read_u16(&mut self) -> Result<u16> {
85        let bytes = self.read_array::<2>()?;
86        Ok(self.endian.read_u16(bytes))
87    }
88
89    /// Performs read_u32.
90    pub fn read_u32(&mut self) -> Result<u32> {
91        let bytes = self.read_array::<4>()?;
92        Ok(self.endian.read_u32(bytes))
93    }
94
95    /// Performs read_u64.
96    pub fn read_u64(&mut self) -> Result<u64> {
97        let bytes = self.read_array::<8>()?;
98        Ok(self.endian.read_u64(bytes))
99    }
100
101    /// Performs read_i32.
102    pub fn read_i32(&mut self) -> Result<i32> {
103        let bytes = self.read_array::<4>()?;
104        Ok(self.endian.read_i32(bytes))
105    }
106
107    /// Performs read_bytes.
108    pub fn read_bytes(&mut self, n: usize) -> Result<&'data [u8]> {
109        let end = self
110            .offset
111            .checked_add(n)
112            .ok_or_else(|| self.bounds_err(n))?;
113        if end > self.data.len() {
114            return Err(self.bounds_err(n));
115        }
116        let slice = &self.data[self.offset..end];
117        self.offset = end;
118        Ok(slice)
119    }
120
121    /// Performs read_fixed_array.
122    pub fn read_fixed_array<const N: usize>(&mut self) -> Result<[u8; N]> {
123        let bytes = self.read_bytes(N)?;
124        let mut arr = [0u8; N];
125        arr.copy_from_slice(bytes);
126        Ok(arr)
127    }
128
129    /// Read a null-terminated C string starting at `abs_offset`.
130    /// Does not advance the cursor.
131    pub fn read_c_string_at(&self, abs_offset: usize, max_len: usize) -> Result<&'data [u8]> {
132        if abs_offset >= self.data.len() {
133            return Err(Error::bounds(abs_offset as u64, 1, self.data.len() as u64));
134        }
135        let limit = (abs_offset + max_len).min(self.data.len());
136        let slice = &self.data[abs_offset..limit];
137        match slice.iter().position(|&b| b == 0) {
138            Some(pos) => Ok(&slice[..pos]),
139            None => Ok(slice),
140        }
141    }
142
143    fn read_array<const N: usize>(&mut self) -> Result<[u8; N]> {
144        let end = self
145            .offset
146            .checked_add(N)
147            .ok_or_else(|| self.bounds_err(N))?;
148        if end > self.data.len() {
149            return Err(self.bounds_err(N));
150        }
151        let mut arr = [0u8; N];
152        arr.copy_from_slice(&self.data[self.offset..end]);
153        self.offset = end;
154        Ok(arr)
155    }
156
157    fn bounds_err(&self, needed: usize) -> Error {
158        Error::bounds(self.offset as u64, needed as u64, self.data.len() as u64)
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    #[test]
167    fn sequential_reads() {
168        let data = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08];
169        let mut r = BinaryReader::new(&data, Endian::Little);
170        assert_eq!(r.read_u32().unwrap(), 0x04030201);
171        assert_eq!(r.read_u32().unwrap(), 0x08070605);
172        assert_eq!(r.remaining(), 0);
173    }
174
175    #[test]
176    fn bounds_error() {
177        let data = [0u8; 2];
178        let mut r = BinaryReader::new(&data, Endian::Little);
179        assert!(r.read_u32().is_err());
180    }
181
182    #[test]
183    fn c_string() {
184        let data = b"hello\0world\0";
185        let r = BinaryReader::new(data, Endian::Little);
186        assert_eq!(r.read_c_string_at(0, 20).unwrap(), b"hello");
187        assert_eq!(r.read_c_string_at(6, 20).unwrap(), b"world");
188    }
189
190    #[test]
191    fn big_endian() {
192        let data = 0xDEADBEEFu32.to_be_bytes();
193        let mut r = BinaryReader::new(&data, Endian::Big);
194        assert_eq!(r.read_u32().unwrap(), 0xDEADBEEF);
195    }
196}