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}