fdt_rs/common/
prop.rs

1use core::mem::size_of;
2use core::str::from_utf8;
3
4use crate::prelude::*;
5
6use crate::base::DevTree;
7use crate::error::DevTreeError;
8use crate::spec::Phandle;
9
10use crate::error::Result;
11
12#[cfg(doc)]
13use crate::base::DevTreeProp;
14
15pub trait PropReader<'dt> {
16    type NodeType;
17
18    /// Returns the buffer associtated with the property's data.
19    #[doc(hidden)]
20    fn propbuf(&self) -> &'dt [u8];
21
22    /// Returns offset of this property's name in the device tree buffer.
23    #[doc(hidden)]
24    fn nameoff(&self) -> usize;
25
26    #[doc(hidden)]
27    fn fdt(&self) -> &DevTree<'dt>;
28
29    /// Returns the name of the property within the device tree.
30    #[inline]
31    fn name(&self) -> Result<&'dt str> {
32        let str_offset = self.fdt().off_dt_strings() + self.nameoff();
33        let name = self.fdt().buf().read_bstring0(str_offset)?;
34        Ok(from_utf8(name)?)
35    }
36
37    /// Returns the length of the property value within the device tree
38    #[inline]
39    #[must_use]
40    fn length(&self) -> usize {
41        self.propbuf().len()
42    }
43
44    /// Returns the node which this property is contained within.
45    fn node(&self) -> Self::NodeType;
46
47    /// Read a big-endian [`u32`] from the provided offset in this device tree property's value.
48    /// Convert the read value into the machines' native [`u32`] format and return it.
49    ///
50    /// If an offset which would cause this read to access memory outside of this property's value
51    /// an [`Err`] containing [`DevTreeError::InvalidOffset`] will be returned.
52    #[inline]
53    fn u32(&self, index: usize) -> Result<u32> {
54        // Safety: propbuf is guaranteed aligned to u32
55        // We'll read without re-checking alignment
56        unsafe {
57            self.propbuf()
58                .unsafe_read_be_u32(index * size_of::<u32>())
59                .or(Err(DevTreeError::InvalidOffset))
60        }
61    }
62
63    /// Read a big-endian [`u64`] from the provided offset in this device tree property's value.
64    /// Convert the read value into the machines' native [`u64`] format and return it.
65    ///
66    /// If an offset which would cause this read to access memory outside of this property's value
67    /// an [`Err`] containing [`DevTreeError::InvalidOffset`] will be returned.
68    #[inline]
69    fn u64(&self, index: usize) -> Result<u64> {
70        self.propbuf()
71            .read_be_u64(index * size_of::<u64>())
72            .or(Err(DevTreeError::InvalidOffset))
73    }
74
75    /// A Phandle is simply defined as a u32 value, as such this method performs the same action as
76    /// [`self.u32`]
77    #[inline]
78    fn phandle(&self, index: usize) -> Result<Phandle> {
79        // Safety: propbuf is guaranteed aligned to u32
80        // We'll read without re-checking alignment
81        unsafe {
82            self.propbuf()
83                .unsafe_read_be_u32(index * size_of::<Phandle>())
84                .or(Err(DevTreeError::InvalidOffset))
85        }
86    }
87
88    /// Returns the string property as a string if it can be parsed as one.
89    /// # Safety
90    ///
91    /// See the safety note of [`PropReader::u32`]
92    #[inline]
93    fn str(&self) -> Result<&'dt str> {
94        self.iter_str().next()?.ok_or(DevTreeError::ParseError)
95    }
96
97    /// Returns the property as a string fallible_iterator.
98    /// # Safety
99    ///
100    /// See the safety note of [`PropReader::u32`]
101    #[inline]
102    fn iter_str(&self) -> StringPropIter<'dt> {
103        StringPropIter::new(self.propbuf())
104    }
105    /// Returns this property's data as a raw slice
106    ///
107    /// # Safety
108    ///
109    /// See the safety note of [`PropReader::get_u32`]
110    #[inline]
111    fn raw(&self) -> &'dt [u8] {
112        self.propbuf()
113    }
114}
115
116use fallible_iterator::FallibleIterator;
117
118#[derive(Debug, Clone)]
119pub struct StringPropIter<'dt> {
120    offset: usize,
121    propbuf: &'dt [u8],
122}
123
124impl<'dt> StringPropIter<'dt> {
125    fn new(propbuf: &'dt [u8]) -> Self {
126        Self { propbuf, offset: 0 }
127    }
128}
129
130impl<'dt> FallibleIterator for StringPropIter<'dt> {
131    type Error = DevTreeError;
132    type Item = &'dt str;
133
134    fn next(&mut self) -> Result<Option<Self::Item>> {
135        if self.offset == self.propbuf.len() {
136            return Ok(None);
137        }
138        if self.offset > self.propbuf.len() {
139            return Err(DevTreeError::InvalidOffset);
140        }
141
142        let u8_slice = self.propbuf.read_bstring0(self.offset)?;
143        // Include null byte
144        self.offset += u8_slice.len() + 1;
145        Ok(Some(from_utf8(u8_slice)?))
146    }
147}