1use crate::error::{Error, Result};
2
3#[derive(Clone, Copy, Debug, Eq, PartialEq)]
12pub enum Endian {
13 Little,
15 Big,
17}
18
19impl Endian {
20 #[must_use]
22 pub const fn native() -> Self {
23 if cfg!(target_endian = "little") {
24 Self::Little
25 } else {
26 Self::Big
27 }
28 }
29}
30
31#[derive(Clone, Debug)]
33pub(crate) struct Cursor<'data> {
34 bytes: &'data [u8],
35 position: usize,
36 endian: Endian,
37}
38
39impl<'data> Cursor<'data> {
40 pub(crate) const fn new(bytes: &'data [u8], endian: Endian) -> Self {
41 Self {
42 bytes,
43 position: 0,
44 endian,
45 }
46 }
47
48 pub(crate) const fn at(bytes: &'data [u8], endian: Endian, position: usize) -> Result<Self> {
49 if position > bytes.len() {
50 return Err(Error::InvalidOffset {
51 offset: position as u64,
52 input_len: bytes.len(),
53 });
54 }
55 Ok(Self {
56 bytes,
57 position,
58 endian,
59 })
60 }
61
62 pub(crate) const fn endian(&self) -> Endian {
63 self.endian
64 }
65
66 pub(crate) const fn position(&self) -> usize {
67 self.position
68 }
69
70 pub(crate) const fn remaining(&self) -> usize {
71 self.bytes.len().saturating_sub(self.position)
72 }
73
74 pub(crate) const fn is_empty(&self) -> bool {
75 self.remaining() == 0
76 }
77
78 pub(crate) fn take(&mut self, count: usize) -> Result<&'data [u8]> {
79 let end = self
80 .position
81 .checked_add(count)
82 .ok_or(Error::Overflow("cursor end offset"))?;
83 let Some(bytes) = self.bytes.get(self.position..end) else {
84 return Err(Error::UnexpectedEof {
85 offset: self.position,
86 needed: count,
87 remaining: self.remaining(),
88 });
89 };
90 self.position = end;
91 Ok(bytes)
92 }
93
94 pub(crate) fn take_array<const N: usize>(&mut self) -> Result<[u8; N]> {
95 let offset = self.position;
96 let remaining = self.remaining();
97 let bytes = self
98 .bytes
99 .get(offset..)
100 .and_then(<[u8]>::first_chunk::<N>)
101 .ok_or(Error::UnexpectedEof {
102 offset,
103 needed: N,
104 remaining,
105 })?;
106 self.position = offset.saturating_add(N);
107 Ok(*bytes)
108 }
109
110 pub(crate) fn read_u8(&mut self) -> Result<u8> {
111 let [byte] = self.take_array()?;
112 Ok(byte)
113 }
114
115 pub(crate) fn read_u16(&mut self) -> Result<u16> {
116 let bytes = self.take_array()?;
117 Ok(match self.endian {
118 Endian::Little => u16::from_le_bytes(bytes),
119 Endian::Big => u16::from_be_bytes(bytes),
120 })
121 }
122
123 pub(crate) fn read_u32(&mut self) -> Result<u32> {
124 let bytes = self.take_array()?;
125 Ok(match self.endian {
126 Endian::Little => u32::from_le_bytes(bytes),
127 Endian::Big => u32::from_be_bytes(bytes),
128 })
129 }
130
131 pub(crate) fn read_u64(&mut self) -> Result<u64> {
132 let bytes = self.take_array()?;
133 Ok(match self.endian {
134 Endian::Little => u64::from_le_bytes(bytes),
135 Endian::Big => u64::from_be_bytes(bytes),
136 })
137 }
138
139 pub(crate) fn read_uint(&mut self, width: u8) -> Result<u64> {
140 match width {
141 1 => return self.read_u8().map(u64::from),
142 2 => return self.read_u16().map(u64::from),
143 4 => return self.read_u32().map(u64::from),
144 8 => return self.read_u64(),
145 3 | 5..=7 => {}
146 _ => {
147 return Err(Error::OutOfRange {
148 field: "integer width",
149 value: u64::from(width),
150 max: 8,
151 });
152 }
153 }
154 let count = usize::from(width);
155 let bytes = self.take(count)?;
156 let mut buffer = [0_u8; 8];
157 let window = match self.endian {
158 Endian::Little => buffer.get_mut(..count),
159 Endian::Big => buffer.get_mut(size_of::<u64>().saturating_sub(count)..),
160 };
161 window
162 .ok_or_else(|| Error::OutOfRange {
163 field: "integer width",
164 value: u64::from(width),
165 max: 8,
166 })?
167 .copy_from_slice(bytes);
168 Ok(match self.endian {
169 Endian::Little => u64::from_le_bytes(buffer),
170 Endian::Big => u64::from_be_bytes(buffer),
171 })
172 }
173}
174
175#[derive(Clone, Debug)]
177pub(crate) struct Encoder {
178 bytes: Vec<u8>,
179 endian: Endian,
180}
181
182impl Encoder {
183 #[cfg(test)]
184 pub(crate) const fn new(endian: Endian) -> Self {
185 Self {
186 bytes: Vec::new(),
187 endian,
188 }
189 }
190
191 pub(crate) fn with_capacity(endian: Endian, capacity: usize) -> Self {
192 Self {
193 bytes: Vec::with_capacity(capacity),
194 endian,
195 }
196 }
197
198 pub(crate) const fn len(&self) -> usize {
199 self.bytes.len()
200 }
201
202 #[cfg(test)]
203 pub(crate) fn as_slice(&self) -> &[u8] {
204 &self.bytes
205 }
206
207 pub(crate) fn into_inner(self) -> Vec<u8> {
208 self.bytes
209 }
210
211 pub(crate) fn write_u8(&mut self, value: u8) {
212 self.bytes.push(value);
213 }
214
215 pub(crate) fn write_u16(&mut self, value: u16) {
216 self.bytes.extend_from_slice(&match self.endian {
217 Endian::Little => value.to_le_bytes(),
218 Endian::Big => value.to_be_bytes(),
219 });
220 }
221
222 pub(crate) fn write_u32(&mut self, value: u32) {
223 self.bytes.extend_from_slice(&match self.endian {
224 Endian::Little => value.to_le_bytes(),
225 Endian::Big => value.to_be_bytes(),
226 });
227 }
228
229 pub(crate) fn write_u64(&mut self, value: u64) {
230 self.bytes.extend_from_slice(&match self.endian {
231 Endian::Little => value.to_le_bytes(),
232 Endian::Big => value.to_be_bytes(),
233 });
234 }
235
236 pub(crate) fn write_uint(&mut self, value: u64, width: u8) -> Result<()> {
237 if !(1..=8).contains(&width) {
238 return Err(Error::OutOfRange {
239 field: "integer width",
240 value: u64::from(width),
241 max: 8,
242 });
243 }
244 let count = usize::from(width);
245 if width < 8 {
246 let max = u64::MAX
247 .checked_shr(u32::from(8_u8.saturating_sub(width)).saturating_mul(8))
248 .unwrap_or(u64::MAX);
249 if value > max {
250 return Err(Error::OutOfRange {
251 field: "fixed-width integer",
252 value,
253 max,
254 });
255 }
256 }
257 let bytes = match self.endian {
258 Endian::Little => value.to_le_bytes(),
259 Endian::Big => value.to_be_bytes(),
260 };
261 let window = match self.endian {
262 Endian::Little => bytes.get(..count),
263 Endian::Big => bytes.get(size_of::<u64>().saturating_sub(count)..),
264 };
265 self.bytes
266 .extend_from_slice(window.ok_or_else(|| Error::OutOfRange {
267 field: "integer width",
268 value: u64::from(width),
269 max: 8,
270 })?);
271 Ok(())
272 }
273
274 pub(crate) fn write_bytes(&mut self, bytes: &[u8]) {
275 self.bytes.extend_from_slice(bytes);
276 }
277
278 pub(crate) fn align_to(&mut self, alignment: usize) -> Result<()> {
279 if alignment == 0 {
280 return Err(Error::InvalidAlignment(alignment));
281 }
282 let remainder = self.bytes.len().checked_rem(alignment).unwrap_or(0);
283 if remainder != 0 {
284 let padding = alignment.saturating_sub(remainder);
285 let new_len = self
286 .bytes
287 .len()
288 .checked_add(padding)
289 .ok_or(Error::Overflow("aligned output length"))?;
290 self.bytes.resize(new_len, 0);
291 }
292 Ok(())
293 }
294
295 pub(crate) fn patch_u32(&mut self, offset: usize, value: u32) -> Result<()> {
296 let bytes = match self.endian {
297 Endian::Little => value.to_le_bytes(),
298 Endian::Big => value.to_be_bytes(),
299 };
300 let end = offset
301 .checked_add(bytes.len())
302 .ok_or(Error::Overflow("patch end offset"))?;
303 let remaining = self.bytes.len().saturating_sub(offset);
304 let destination = self
305 .bytes
306 .get_mut(offset..end)
307 .ok_or(Error::UnexpectedEof {
308 offset,
309 needed: bytes.len(),
310 remaining,
311 })?;
312 destination.copy_from_slice(&bytes);
313 Ok(())
314 }
315
316 #[cfg(test)]
317 pub(crate) fn patch_uint(&mut self, offset: usize, value: u64, width: u8) -> Result<()> {
318 let mut encoded = Self::new(self.endian);
319 encoded.write_uint(value, width)?;
320 let end = offset
321 .checked_add(usize::from(width))
322 .ok_or(Error::Overflow("patch end offset"))?;
323 let remaining = self.bytes.len().saturating_sub(offset);
324 let destination = self
325 .bytes
326 .get_mut(offset..end)
327 .ok_or_else(|| Error::UnexpectedEof {
328 offset,
329 needed: usize::from(width),
330 remaining,
331 })?;
332 destination.copy_from_slice(encoded.as_slice());
333 Ok(())
334 }
335}
336
337#[cfg(test)]
338mod tests {
339 use super::{Cursor, Encoder, Endian};
340
341 #[test]
342 fn fixed_width_round_trip_both_endians() {
343 for endian in [Endian::Little, Endian::Big] {
344 let mut output = Encoder::new(endian);
345 output.write_u8(0x12);
346 output.write_u16(0x3456);
347 output.write_u32(0x789a_bcde);
348 output.write_u64(0x0123_4567_89ab_cdef);
349 output.write_uint(0xa1_b2_c3, 3).unwrap();
350
351 let mut input = Cursor::new(output.as_slice(), endian);
352 assert_eq!(input.read_u8().unwrap(), 0x12);
353 assert_eq!(input.read_u16().unwrap(), 0x3456);
354 assert_eq!(input.read_u32().unwrap(), 0x789a_bcde);
355 assert_eq!(input.read_u64().unwrap(), 0x0123_4567_89ab_cdef);
356 assert_eq!(input.read_uint(3).unwrap(), 0xa1_b2_c3);
357 assert!(input.is_empty());
358 }
359 }
360
361 #[test]
362 fn bounds_and_alignment_are_checked() {
363 let mut input = Cursor::new(&[1, 2], Endian::Little);
364 assert!(input.read_u32().is_err());
365
366 let mut output = Encoder::new(Endian::Little);
367 output.write_u8(1);
368 output.align_to(4).unwrap();
369 assert_eq!(output.as_slice(), &[1, 0, 0, 0]);
370 assert!(output.patch_u32(1, 7).is_err());
371 }
372}