Skip to main content

fdt_raw/
data.rs

1//! Low-level data access primitives for FDT parsing.
2//!
3//! This module provides raw data access types for reading FDT binary format,
4//! including bytes slices, readers, and various iterators.
5
6use core::{
7    ffi::CStr,
8    ops::{Deref, Range},
9};
10
11use crate::define::{FdtError, Token};
12
13/// Size of a 32-bit (4-byte) value in bytes.
14/// Used frequently in FDT parsing for alignment and value sizes.
15pub(crate) const U32_SIZE: usize = 4;
16
17/// Memory reservation entry size in bytes (address + size, each 8 bytes).
18pub(crate) const MEM_RSV_ENTRY_SIZE: usize = 16;
19
20/// A view into a byte slice with a specific range.
21///
22/// `Bytes` provides a window into FDT data with range tracking and
23/// convenience methods for creating readers and iterators. This allows
24/// zero-copy parsing by maintaining references to the original data.
25///
26/// # Examples
27///
28/// ```ignore
29/// let bytes = Bytes::new(&data);
30/// let slice = bytes.slice(10..20);
31/// let reader = slice.reader();
32/// ```
33#[derive(Clone)]
34pub struct Bytes<'a> {
35    /// Reference to the complete original data buffer
36    pub(crate) all: &'a [u8],
37    /// The active range within the original buffer
38    range: Range<usize>,
39}
40
41impl Deref for Bytes<'_> {
42    type Target = [u8];
43
44    fn deref(&self) -> &Self::Target {
45        &self.all[self.range.clone()]
46    }
47}
48
49impl<'a> Bytes<'a> {
50    /// Creates a new `Bytes` from the entire byte slice.
51    ///
52    /// # Examples
53    ///
54    /// ```ignore
55    /// let bytes = Bytes::new(&my_data);
56    /// ```
57    pub fn new(all: &'a [u8]) -> Self {
58        Self {
59            all,
60            range: 0..all.len(),
61        }
62    }
63
64    /// Creates a new `Bytes` from a subrange of the current data.
65    ///
66    /// # Panics
67    ///
68    /// Panics if `range.end` exceeds the current length.
69    pub fn slice(&self, range: Range<usize>) -> Self {
70        assert!(range.end <= self.len());
71        Self {
72            all: self.all,
73            range: (self.range.start + range.start)..(self.range.start + range.end),
74        }
75    }
76
77    /// Returns the underlying byte slice as reference.
78    pub fn as_slice(&self) -> &'a [u8] {
79        &self.all[self.range.clone()]
80    }
81
82    /// Returns the length of the byte slice.
83    pub fn len(&self) -> usize {
84        self.range.end - self.range.start
85    }
86
87    /// Creates a reader for sequential reading from this position.
88    pub fn reader(&self) -> Reader<'a> {
89        Reader {
90            bytes: self.slice(0..self.len()),
91            iter: 0,
92        }
93    }
94
95    /// Creates a reader starting at a specific position.
96    ///
97    /// # Panics
98    ///
99    /// Panics if `position` is greater than or equal to the current length.
100    pub fn reader_at(&self, position: usize) -> Reader<'a> {
101        assert!(position < self.len());
102        Reader {
103            bytes: self.slice(position..self.len()),
104            iter: 0,
105        }
106    }
107
108    /// Creates a u32 iterator over this data.
109    pub fn as_u32_iter(&self) -> U32Iter<'a> {
110        U32Iter {
111            reader: self.reader(),
112        }
113    }
114
115    /// Creates a string iterator over this data.
116    pub fn as_str_iter(&self) -> StrIter<'a> {
117        StrIter {
118            reader: self.reader(),
119        }
120    }
121
122    /// Checks if the byte slice is empty.
123    pub fn is_empty(&self) -> bool {
124        self.len() == 0
125    }
126}
127
128/// Sequential reader for parsing FDT data structures.
129///
130/// `Reader` provides sequential read access with position tracking for
131/// parsing FDT binary format. It maintains a current position and can
132/// backtrack if needed.
133///
134/// # Examples
135///
136/// ```ignore
137/// let mut reader = bytes.reader();
138/// let value = reader.read_u32()?;
139/// let str = reader.read_cstr()?;
140/// ```
141#[derive(Clone)]
142pub struct Reader<'a> {
143    /// The byte slice being read from
144    pub(crate) bytes: Bytes<'a>,
145    /// Current read position within the bytes
146    pub(crate) iter: usize,
147}
148
149impl<'a> Reader<'a> {
150    /// Returns the current read position in the original data.
151    pub fn position(&self) -> usize {
152        self.bytes.range.start + self.iter
153    }
154
155    /// Returns the remaining unread data as a `Bytes`.
156    pub fn remain(&self) -> Bytes<'a> {
157        self.bytes.slice(self.iter..self.bytes.len())
158    }
159
160    /// Reads the specified number of bytes, advancing the position.
161    ///
162    /// Returns `None` if insufficient bytes remain.
163    pub fn read_bytes(&mut self, size: usize) -> Option<Bytes<'a>> {
164        if self.iter + size > self.bytes.len() {
165            return None;
166        }
167        let start = self.iter;
168        self.iter += size;
169        Some(self.bytes.slice(start..start + size))
170    }
171
172    /// Reads a big-endian u32 value.
173    pub fn read_u32(&mut self) -> Option<u32> {
174        let bytes = self.read_bytes(U32_SIZE)?;
175        Some(u32::from_be_bytes(bytes.as_slice().try_into().unwrap()))
176    }
177
178    /// Reads a big-endian u64 value (composed of two u32 values).
179    pub fn read_u64(&mut self) -> Option<u64> {
180        let high = self.read_u32()? as u64;
181        let low = self.read_u32()? as u64;
182        Some((high << 32) | low)
183    }
184
185    /// Reads a value composed of the specified number of cells.
186    ///
187    /// Each cell is 4 bytes (a u32). The cells are combined into a u64 value.
188    pub fn read_cells(&mut self, cell_count: usize) -> Option<u64> {
189        let mut value: u64 = 0;
190        for _ in 0..cell_count {
191            let cell = self.read_u32()? as u64;
192            value = (value << 32) | cell;
193        }
194        Some(value)
195    }
196
197    /// Reads a token from the FDT structure block.
198    pub fn read_token(&mut self) -> Result<Token, FdtError> {
199        let bytes = self.read_bytes(U32_SIZE).ok_or(FdtError::BufferTooSmall {
200            pos: self.position(),
201        })?;
202        Ok(u32::from_be_bytes(bytes.as_slice().try_into().unwrap()).into())
203    }
204
205    /// Moves the read position back by the specified size.
206    pub fn backtrack(&mut self, size: usize) {
207        assert!(size <= self.iter);
208        self.iter -= size;
209    }
210}
211
212/// Iterator over u32 values in FDT data.
213///
214/// Reads big-endian u32 values sequentially from the underlying data.
215/// Each iteration consumes 4 bytes.
216///
217/// # Examples
218///
219/// ```ignore
220/// let mut iter = bytes.as_u32_iter();
221/// while let Some(value) = iter.next() {
222///     println!("Value: {:#x}", value);
223/// }
224/// ```
225#[derive(Clone)]
226pub struct U32Iter<'a> {
227    /// The underlying reader for accessing FDT data
228    pub reader: Reader<'a>,
229}
230
231impl Iterator for U32Iter<'_> {
232    type Item = u32;
233
234    fn next(&mut self) -> Option<Self::Item> {
235        let bytes = self.reader.read_bytes(U32_SIZE)?;
236        Some(u32::from_be_bytes(bytes.as_slice().try_into().unwrap()))
237    }
238}
239
240/// Iterator over null-terminated strings in FDT data.
241///
242/// Reads null-terminated (C-style) strings sequentially from the underlying data.
243/// Each iteration consumes the string content plus its null terminator.
244///
245/// # Examples
246///
247/// ```ignore
248/// let mut iter = bytes.as_str_iter();
249/// while let Some(s) = iter.next() {
250///     println!("String: {}", s);
251/// }
252/// ```
253#[derive(Clone)]
254pub struct StrIter<'a> {
255    /// The underlying reader for accessing FDT data
256    pub reader: Reader<'a>,
257}
258
259impl<'a> Iterator for StrIter<'a> {
260    type Item = &'a str;
261
262    fn next(&mut self) -> Option<Self::Item> {
263        let remain = self.reader.remain();
264        if remain.is_empty() {
265            return None;
266        }
267        let s = CStr::from_bytes_until_nul(remain.as_slice())
268            .ok()?
269            .to_str()
270            .ok()?;
271        let str_len = s.len() + 1; // including null terminator
272        self.reader.read_bytes(str_len)?; // advance read position
273        Some(s)
274    }
275}