1use core::mem::size_of;
5use core::ptr;
6
7use num_traits::FromPrimitive;
8
9use crate::base::DevTree;
10use crate::error::{DevTreeError, Result};
11use crate::priv_util::SliceRead;
12use crate::spec::{fdt_prop_header, FdtTok, MAX_NODE_NAME_LEN};
13
14use fallible_iterator::FallibleIterator;
15
16pub unsafe fn next_devtree_token<'a>(
32 buf: &'a [u8],
33 off: &mut usize,
34) -> Result<Option<ParsedTok<'a>>> {
35 debug_assert!(buf.as_ptr().add(*off) as usize % size_of::<u32>() == 0);
38 debug_assert!(buf.len() > (*off + size_of::<u32>()));
39
40 let fdt_tok_val = buf.unsafe_read_be_u32(*off)?;
41 *off += size_of::<u32>();
42
43 match FromPrimitive::from_u32(fdt_tok_val) {
44 Some(FdtTok::BeginNode) => {
45 let name = buf.nread_bstring0(*off, MAX_NODE_NAME_LEN - 1)?;
47
48 *off += name.len() + 1;
50 *off += buf.as_ptr().add(*off).align_offset(size_of::<u32>());
52
53 Ok(Some(ParsedTok::BeginNode(ParsedBeginNode { name })))
54 }
55 Some(FdtTok::Prop) => {
56 let header_slice = buf
58 .get(*off..*off + size_of::<fdt_prop_header>())
59 .ok_or(DevTreeError::ParseError)?;
60 assert_eq_align!(fdt_prop_header, u32);
65 #[allow(clippy::cast_ptr_alignment)]
66 let header = &*(header_slice.as_ptr() as *const fdt_prop_header);
67 let prop_len = u32::from(header.len) as usize;
68
69 *off += size_of::<fdt_prop_header>();
71 let prop_buf = buf
73 .get(*off..*off + prop_len)
74 .ok_or(DevTreeError::ParseError)?;
75
76 *off += prop_buf.len();
78 *off += buf.as_ptr().add(*off).align_offset(size_of::<u32>());
80
81 let name_offset = u32::from(header.nameoff) as usize;
82 if name_offset > buf.len() {
83 return Err(DevTreeError::ParseError);
84 }
85 let name_offset = name_offset;
86
87 Ok(Some(ParsedTok::Prop(ParsedProp {
88 prop_buf,
89 name_offset,
90 })))
91 }
92 Some(FdtTok::EndNode) => Ok(Some(ParsedTok::EndNode)),
93 Some(FdtTok::Nop) => Ok(Some(ParsedTok::Nop)),
94 Some(FdtTok::End) => Ok(None),
95 None => {
96 Err(DevTreeError::ParseError)
98 }
99 }
100}
101
102#[derive(Clone, Debug)]
103pub struct ParsedBeginNode<'a> {
104 pub name: &'a [u8],
105}
106
107impl<'a> PartialEq for ParsedBeginNode<'a> {
108 fn eq(&self, other: &Self) -> bool {
109 ptr::eq(self.name, other.name)
110 }
111}
112
113#[derive(Clone, Debug)]
114pub struct ParsedProp<'a> {
115 pub prop_buf: &'a [u8],
116 pub name_offset: usize,
117}
118
119impl<'a> PartialEq for ParsedProp<'a> {
120 fn eq(&self, other: &Self) -> bool {
121 ptr::eq(self.prop_buf, other.prop_buf) && self.name_offset == other.name_offset
122 }
123}
124
125#[derive(Clone, Debug, PartialEq)]
127pub enum ParsedTok<'a> {
128 BeginNode(ParsedBeginNode<'a>),
129 EndNode,
130 Prop(ParsedProp<'a>),
131 Nop,
132}
133
134#[derive(Debug, PartialEq)]
135pub struct DevTreeParseIter<'r, 'dt: 'r> {
136 pub offset: usize,
137 pub fdt: &'r DevTree<'dt>,
138}
139
140impl<'r, 'dt: 'r> DevTreeParseIter<'r, 'dt> {
141 pub fn new(fdt: &'r DevTree<'dt>) -> Self {
142 Self {
143 offset: fdt.off_dt_struct(),
144 fdt,
145 }
146 }
147}
148
149impl<'dt, 'a: 'dt> FallibleIterator for DevTreeParseIter<'dt, 'a> {
150 type Error = DevTreeError;
151 type Item = ParsedTok<'a>;
152
153 fn next(&mut self) -> Result<Option<Self::Item>> {
154 unsafe { next_devtree_token(self.fdt.buf(), &mut self.offset) }
157 }
158}