macho_core/format/io/
reader.rs1use crate::error::{Error, Result};
2use crate::format::io::endian::Endian;
3
4pub struct BinaryReader<'data> {
6 data: &'data [u8],
7 endian: Endian,
8 offset: usize,
9}
10
11impl<'data> BinaryReader<'data> {
12 pub fn new(data: &'data [u8], endian: Endian) -> Self {
14 Self {
15 data,
16 endian,
17 offset: 0,
18 }
19 }
20
21 pub fn at_offset(data: &'data [u8], endian: Endian, offset: usize) -> Self {
23 Self {
24 data,
25 endian,
26 offset,
27 }
28 }
29
30 pub fn offset(&self) -> usize {
32 self.offset
33 }
34
35 pub fn remaining(&self) -> usize {
37 self.data.len().saturating_sub(self.offset)
38 }
39
40 pub fn len(&self) -> usize {
42 self.data.len()
43 }
44
45 pub fn is_empty(&self) -> bool {
47 self.data.is_empty()
48 }
49
50 pub fn endian(&self) -> Endian {
52 self.endian
53 }
54
55 pub fn seek(&mut self, offset: usize) {
57 self.offset = offset;
58 }
59
60 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 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 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 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 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 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 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 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 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}