esp_partition_table/
entry.rs1use crate::{utils, PartitionError, PartitionType};
2
3#[cfg(feature = "heapless")]
4use heapless::String;
5
6pub type PartitionBuffer = [u8; PartitionEntry::SIZE];
8
9#[derive(Clone, Debug, Default, PartialEq, Eq)]
24pub struct PartitionEntry {
25 pub type_: PartitionType,
27
28 pub offset: u32,
30
31 pub size: usize,
33
34 #[cfg(feature = "heapless")]
36 pub name: String<{ Self::MAX_NAME_LEN }>,
37
38 #[cfg(not(feature = "heapless"))]
39 name: [u8; Self::MAX_NAME_LEN],
40
41 pub encrypted: bool,
43}
44
45impl PartitionEntry {
46 pub const MAGIC: [u8; 2] = [0xAA, 0x50];
48
49 pub const SIZE: usize = 32;
51
52 pub const MAX_NAME_LEN: usize = 16;
54
55 pub fn new(
57 type_: impl Into<PartitionType>,
58 offset: u32,
59 size: usize,
60 name: impl AsRef<str>,
61 encrypted: bool,
62 ) -> Result<Self, PartitionError> {
63 let name = name.as_ref();
64
65 #[cfg(feature = "heapless")]
66 let name = name.try_into().map_err(|_| PartitionError::InvalidString)?;
67
68 #[cfg(not(feature = "heapless"))]
69 let name = {
70 let mut name_data = [0u8; Self::MAX_NAME_LEN];
71 utils::name_into(&mut name_data, name)?;
72 name_data
73 };
74
75 Ok(Self {
76 type_: type_.into(),
77 offset,
78 size,
79 name,
80 encrypted,
81 })
82 }
83
84 pub fn set_offset(&mut self, offset: u32) -> Result<(), PartitionError> {
86 self.type_.check_offset(offset)?;
87 self.offset = offset;
88 Ok(())
89 }
90
91 pub fn name(&self) -> &str {
93 #[cfg(not(feature = "heapless"))]
94 {
95 let name = utils::name_trim(&self.name);
96 unsafe { core::str::from_utf8_unchecked(name) }
98 }
99
100 #[cfg(feature = "heapless")]
101 {
102 &self.name
103 }
104 }
105
106 pub fn set_name(&mut self, name: impl AsRef<str>) -> Result<(), PartitionError> {
108 let name = name.as_ref();
109
110 #[cfg(feature = "heapless")]
111 {
112 self.name = name.try_into().map_err(|_| PartitionError::InvalidString)?;
113 Ok(())
114 }
115
116 #[cfg(not(feature = "heapless"))]
117 {
118 utils::name_into(&mut self.name, name)
119 }
120 }
121
122 pub fn from_bytes(data: &PartitionBuffer) -> Result<Self, PartitionError> {
124 let (magic, data) = data
125 .split_first_chunk()
126 .ok_or(PartitionError::NotEnoughData)?;
127 if magic != &Self::MAGIC {
128 return Err(PartitionError::InvalidMagic);
129 }
130
131 let (type_data, data) = data
132 .split_first_chunk()
133 .ok_or(PartitionError::NotEnoughData)?;
134 let type_ = type_data.try_into()?;
135
136 let (offset_data, data) = data
137 .split_first_chunk()
138 .ok_or(PartitionError::NotEnoughData)?;
139 let offset = u32::from_le_bytes(*offset_data);
140
141 let (size_data, data) = data
142 .split_first_chunk()
143 .ok_or(PartitionError::NotEnoughData)?;
144 let size = u32::from_le_bytes(*size_data) as usize;
145
146 let (name_data, data) = data
147 .split_first_chunk()
148 .ok_or(PartitionError::NotEnoughData)?;
149 let _name_str = utils::name_from(name_data)?;
150
151 #[cfg(feature = "heapless")]
152 let name = _name_str
153 .try_into()
154 .map_err(|_| PartitionError::TooManyData)?;
155
156 #[cfg(not(feature = "heapless"))]
157 let name = *name_data;
158
159 let (flags_data, _) = data
160 .split_first_chunk()
161 .ok_or(PartitionError::NotEnoughData)?;
162 let flags = u32::from_le_bytes(*flags_data);
163
164 let encrypted = flags & 0x01 != 0;
165
166 Ok(Self {
167 type_,
168 offset,
169 size,
170 name,
171 encrypted,
172 })
173 }
174
175 pub fn to_bytes(&self, data: &mut PartitionBuffer) -> Result<(), PartitionError> {
177 self.type_.check_offset(self.offset)?;
178
179 let (magic_data, data) = data
180 .split_first_chunk_mut()
181 .ok_or(PartitionError::NotEnoughData)?;
182 *magic_data = Self::MAGIC;
183
184 let (type_data, data) = data
185 .split_first_chunk_mut()
186 .ok_or(PartitionError::NotEnoughData)?;
187 self.type_.to_bytes(type_data)?;
188
189 let (offset_data, data) = data
190 .split_first_chunk_mut()
191 .ok_or(PartitionError::NotEnoughData)?;
192 *offset_data = self.offset.to_le_bytes();
193
194 let (size_data, data) = data
195 .split_first_chunk_mut()
196 .ok_or(PartitionError::NotEnoughData)?;
197 *size_data = (self.size as u32).to_le_bytes();
198
199 let (name_data, data) = data
200 .split_first_chunk_mut()
201 .ok_or(PartitionError::NotEnoughData)?;
202
203 #[cfg(feature = "heapless")]
204 utils::name_into(name_data, self.name.as_str())?;
205
206 #[cfg(not(feature = "heapless"))]
207 {
208 *name_data = self.name;
209 }
210
211 let (flags_data, _) = data
212 .split_first_chunk_mut()
213 .ok_or(PartitionError::NotEnoughData)?;
214 *flags_data = (self.encrypted as u32).to_le_bytes();
215
216 Ok(())
217 }
218}
219
220impl AsRef<PartitionEntry> for PartitionEntry {
221 fn as_ref(&self) -> &Self {
222 self
223 }
224}
225
226impl TryFrom<&[u8]> for PartitionEntry {
227 type Error = PartitionError;
228
229 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
230 <&PartitionBuffer>::try_from(data)
231 .map_err(|_| PartitionError::NotEnoughData)
232 .and_then(Self::try_from)
233 }
234}
235
236impl TryFrom<&PartitionBuffer> for PartitionEntry {
237 type Error = PartitionError;
238
239 fn try_from(data: &PartitionBuffer) -> Result<Self, Self::Error> {
240 Self::from_bytes(data)
241 }
242}
243
244pub type Md5Data = [u8; 16];
246
247#[derive(Clone, Debug, Default, PartialEq, Eq)]
258pub struct PartitionMd5 {
259 pub data: Md5Data,
261}
262
263impl From<PartitionMd5> for Md5Data {
264 fn from(md5: PartitionMd5) -> Self {
265 md5.data
266 }
267}
268
269impl From<Md5Data> for PartitionMd5 {
270 fn from(data: Md5Data) -> Self {
271 Self { data }
272 }
273}
274
275#[cfg(feature = "md5")]
276impl From<md5::Digest> for PartitionMd5 {
277 fn from(digest: md5::Digest) -> Self {
278 Self {
279 data: digest.into(),
280 }
281 }
282}
283
284impl PartitionMd5 {
285 pub const MAGIC: [u8; 2] = [0xeb, 0xeb];
287
288 pub const RESERVED_SIZE: usize = 14;
290
291 pub const RESERVED_DATA: u8 = 0xff;
293
294 pub fn from_bytes(data: &PartitionBuffer) -> Result<Self, PartitionError> {
296 let (magic, data) = data
297 .split_first_chunk()
298 .ok_or(PartitionError::NotEnoughData)?;
299 if magic != &Self::MAGIC {
300 return Err(PartitionError::InvalidMagic);
301 }
302
303 let (reserved_data, data) = data
304 .split_first_chunk::<{ Self::RESERVED_SIZE }>()
305 .ok_or(PartitionError::NotEnoughData)?;
306 for reserved in reserved_data {
307 if *reserved != Self::RESERVED_DATA {
308 return Err(PartitionError::InvalidMagic);
309 }
310 }
311
312 let (md5_data, _) = data
313 .split_first_chunk()
314 .ok_or(PartitionError::NotEnoughData)?;
315
316 Ok(Self { data: *md5_data })
317 }
318
319 pub fn to_bytes(&self, data: &mut PartitionBuffer) -> Result<(), PartitionError> {
321 let (magic_data, data) = data
322 .split_first_chunk_mut()
323 .ok_or(PartitionError::NotEnoughData)?;
324 *magic_data = Self::MAGIC;
325
326 let (reserved_data, data) = data
327 .split_first_chunk_mut::<{ Self::RESERVED_SIZE }>()
328 .ok_or(PartitionError::NotEnoughData)?;
329 reserved_data.fill(Self::RESERVED_DATA);
330
331 let (md5_data, _) = data
332 .split_first_chunk_mut()
333 .ok_or(PartitionError::NotEnoughData)?;
334 *md5_data = self.data;
335
336 Ok(())
337 }
338}
339
340impl TryFrom<&[u8]> for PartitionMd5 {
341 type Error = PartitionError;
342
343 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
344 <&PartitionBuffer>::try_from(data)
345 .map_err(|_| PartitionError::NotEnoughData)
346 .and_then(Self::try_from)
347 }
348}
349
350impl TryFrom<&PartitionBuffer> for PartitionMd5 {
351 type Error = PartitionError;
352
353 fn try_from(data: &PartitionBuffer) -> Result<Self, Self::Error> {
354 Self::from_bytes(data)
355 }
356}