1use chrono::DateTime;
2
3pub struct ByteReader<'a> {
4 data: &'a [u8],
5 offset: usize,
6}
7
8impl<'a> ByteReader<'a> {
9 pub fn new(data: &'a [u8]) -> Self {
10 ByteReader { data, offset: 0 }
11 }
12
13 pub fn u8(&mut self) -> u8 {
14 if self.offset >= self.data.len() {
15 panic!(
16 "Attempted to read u8 at offset {} but data length is {}",
17 self.offset,
18 self.data.len()
19 );
20 }
21 let val = self.data[self.offset];
22 self.offset += 1;
23 val
24 }
25
26 pub fn u16(&mut self) -> u16 {
27 if self.offset + 2 > self.data.len() {
28 panic!(
29 "Attempted to read u16 at offset {} but data length is {}",
30 self.offset,
31 self.data.len()
32 );
33 }
34 let val = u16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().unwrap());
35 self.offset += 2;
36 val
37 }
38
39 pub fn u32(&mut self) -> u32 {
40 if self.offset + 4 > self.data.len() {
41 panic!(
42 "Attempted to read u32 at offset {} but data length is {}",
43 self.offset,
44 self.data.len()
45 );
46 }
47 let val = u32::from_le_bytes(self.data[self.offset..self.offset + 4].try_into().unwrap());
48 self.offset += 4;
49 val
50 }
51
52 pub fn u64(&mut self) -> u64 {
53 if self.offset + 8 > self.data.len() {
54 panic!(
55 "Attempted to read u64 at offset {} but data length is {}",
56 self.offset,
57 self.data.len()
58 );
59 }
60 let val = u64::from_le_bytes(self.data[self.offset..self.offset + 8].try_into().unwrap());
61 self.offset += 8;
62 val
63 }
64
65 pub fn i8(&mut self) -> i8 {
66 if self.offset >= self.data.len() {
67 panic!(
68 "Attempted to read i8 at offset {} but data length is {}",
69 self.offset,
70 self.data.len()
71 );
72 }
73 let val = self.data[self.offset] as i8;
74 self.offset += 1;
75 val
76 }
77
78 pub fn i16(&mut self) -> i16 {
79 if self.offset + 2 > self.data.len() {
80 panic!(
81 "Attempted to read i16 at offset {} but data length is {}",
82 self.offset,
83 self.data.len()
84 );
85 }
86 let val = i16::from_le_bytes(self.data[self.offset..self.offset + 2].try_into().unwrap());
87 self.offset += 2;
88 val
89 }
90
91 pub fn i32(&mut self) -> i32 {
92 if self.offset + 4 > self.data.len() {
93 panic!(
94 "Attempted to read i32 at offset {} but data length is {}",
95 self.offset,
96 self.data.len()
97 );
98 }
99 let val = i32::from_le_bytes(self.data[self.offset..self.offset + 4].try_into().unwrap());
100 self.offset += 4;
101 val
102 }
103
104 pub fn i64(&mut self) -> i64 {
105 if self.offset + 8 > self.data.len() {
106 panic!(
107 "Attempted to read i64 at offset {} but data length is {}",
108 self.offset,
109 self.data.len()
110 );
111 }
112 let val = i64::from_le_bytes(self.data[self.offset..self.offset + 8].try_into().unwrap());
113 self.offset += 8;
114 val
115 }
116
117 pub fn bool(&mut self) -> bool {
118 let byte = self.u8();
119 byte != 0
121 }
122
123 pub fn bits(&mut self) -> Vec<bool> {
124 let byte = self.u8(); (0..8).map(|i| (byte & (1 << i)) != 0).collect()
126 }
127
128 pub fn bytes(&mut self, count: usize) -> &'a [u8] {
129 if self.offset + count > self.data.len() {
130 panic!(
131 "Attempted to read {} bytes at offset {} but data length is {}",
132 count,
133 self.offset,
134 self.data.len()
135 );
136 }
137 let slice = &self.data[self.offset..self.offset + count];
138 self.offset += count;
139 slice
140 }
141
142 pub fn peek_bytes(&self, count: usize) -> &'a [u8] {
144 if self.offset + count > self.data.len() {
145 panic!(
146 "Attempted to peek {} bytes at offset {} but data length is {}",
147 count,
148 self.offset,
149 self.data.len()
150 );
151 }
152 &self.data[self.offset..self.offset + count]
153 }
154
155 pub fn read_until(&mut self, address: usize) -> Vec<u8> {
156 let end = std::cmp::min(address, self.data.len());
157 if self.offset >= end {
158 return Vec::new(); }
160 let slice = &self.data[self.offset..end];
161 self.offset = end; slice.to_vec()
163 }
164
165 pub fn offset(&self) -> usize {
166 self.offset
167 }
168
169 pub fn seek(&mut self, offset: usize) {
170 self.offset = offset;
171 }
172
173 pub fn uleb128(&mut self) -> u64 {
174 let mut value = 0u64;
175 let mut shift = 0;
176 loop {
177 let byte = self.u8();
178 value |= ((byte & 0x7F) as u64) << shift;
179 if (byte & 0x80) == 0 {
180 break;
181 }
182 shift += 7;
183 }
184 value
185 }
186
187 pub fn string(&mut self, size: Option<usize>) -> String {
188 let size = size.unwrap_or_else(|| self.uleb128() as usize);
189 let bytes = self.bytes(size);
190 bytes.iter().map(|&b| b as char).collect() }
192
193 pub fn uuid(&mut self) -> String {
194 let bytes = self.bytes(16);
195 format!(
196 "{:02x}{:02x}{:02x}{:02x}-\
197 {:02x}{:02x}-\
198 {:02x}{:02x}-\
199 {:02x}{:02x}-\
200 {:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
201 bytes[0],
202 bytes[1],
203 bytes[2],
204 bytes[3],
205 bytes[4],
206 bytes[5],
207 bytes[6],
208 bytes[7],
209 bytes[8],
210 bytes[9],
211 bytes[10],
212 bytes[11],
213 bytes[12],
214 bytes[13],
215 bytes[14],
216 bytes[15],
217 )
218 }
219
220 pub fn datetime(&mut self) -> String {
221 let raw = self.u64(); let _kind: u64 = (raw >> 62) & 0b11;
224 let ticks: u64 = raw & 0x3FFF_FFFF_FFFF_FFFF; let unix_offset: u64 = 621355968000000000;
235 if ticks < unix_offset {
236 return "⚠️ Before UNIX epoch".to_string();
237 }
238
239 let unix_ticks: u64 = ticks - unix_offset;
240 let secs: u64 = unix_ticks / 10_000_000;
241 let nsecs: u64 = (unix_ticks % 10_000_000) * 100;
242
243 match DateTime::from_timestamp(secs as i64, nsecs as u32) {
244 Some(dt) => {
245 dt.format("%Y-%m-%d %H:%M:%S%.f").to_string()
248 }
249 _ => "⚠️ Invalid datetime".to_string(),
250 }
251 }
252
253 pub fn f32(&mut self) -> f32 {
254 if self.offset + 4 > self.data.len() {
255 panic!(
256 "Attempted to read f32 at offset {} but data length is {}",
257 self.offset,
258 self.data.len()
259 );
260 }
261 let bytes = self.bytes(4);
262 f32::from_le_bytes(bytes.try_into().unwrap())
263 }
264
265 pub fn f64(&mut self) -> f64 {
266 if self.offset + 8 > self.data.len() {
267 panic!(
268 "Attempted to read f64 at offset {} but data length is {}",
269 self.offset,
270 self.data.len()
271 );
272 }
273 let bytes = self.bytes(8);
274 f64::from_le_bytes(bytes.try_into().unwrap())
275 }
276
277 pub fn slice_bytes(&self, start: usize, end: usize) -> Vec<u8> {
278 if start > end || end > self.data.len() {
279 panic!(
280 "Invalid slice range: {}..{} (data len {})",
281 start,
282 end,
283 self.data.len()
284 );
285 }
286 self.data[start..end].to_vec()
287 }
288}