Skip to content

Commit 0bdf4be

Browse files
committed
pldm-platform: Add AsciiString
This is a fixed length null terminated string for encoding/decoding PDRs, wrapping the underlying VecWrap bytes. Signed-off-by: Matt Johnston <[email protected]>
1 parent fe5d5d4 commit 0bdf4be

File tree

2 files changed

+95
-11
lines changed

2 files changed

+95
-11
lines changed

pldm-file/examples/host.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,6 @@ fn handle_get_pdr(
173173
.try_into()
174174
.context("File size > u32")?;
175175

176-
// null terminated filename
177-
let mut file_name = FILENAME.as_bytes().to_vec();
178-
file_name.push(0x00);
179-
let file_name = pldm_platform::Vec::from_slice(&file_name).unwrap();
180-
181176
let pdr_resp = GetPDRResp::new_single(
182177
PDR_HANDLE,
183178
PdrRecord::FileDescriptor(FileDescriptorPdr {
@@ -196,7 +191,7 @@ fn handle_get_pdr(
196191
file_max_size,
197192
// TODO
198193
file_max_desc_count: 1,
199-
file_name: file_name.into(),
194+
file_name: FILENAME.try_into().expect("Filename too long"),
200195
oem_file_name: Default::default(),
201196
}),
202197
)?;

pldm-platform/src/proto.rs

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,97 @@ where
260260
}
261261
}
262262

263+
/// A null terminated ascii string.
264+
#[derive(DekuWrite, Default, Clone)]
265+
pub struct AsciiString<const N: usize>(pub VecWrap<u8, N>);
266+
267+
impl<const N: usize> AsciiString<N> {
268+
/// Return the length of the string
269+
///
270+
/// Null terminator is included.
271+
pub fn len(&self) -> usize {
272+
self.0.len()
273+
}
274+
275+
/// Returns whether `len() == 0`.
276+
pub fn is_empty(&self) -> bool {
277+
self.0.is_empty()
278+
}
279+
280+
/// Return the underlying bytes.
281+
///
282+
/// This includes any null terminator.
283+
pub fn as_bytes(&self) -> &[u8] {
284+
&self.0
285+
}
286+
}
287+
288+
impl<const N: usize> core::fmt::Debug for AsciiString<N> {
289+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
290+
write!(f, "\"")?;
291+
for c in self.0.escape_ascii() {
292+
write!(f, "{}", char::from(c))?;
293+
}
294+
write!(f, "\"")?;
295+
if !self.0.is_empty() && !self.0.ends_with(&[0x00]) {
296+
write!(f, " (missing null terminator)")?;
297+
}
298+
Ok(())
299+
}
300+
}
301+
302+
impl<const N: usize> TryFrom<&[u8]> for AsciiString<N> {
303+
type Error = ();
304+
305+
/// Convert from a byte slice.
306+
///
307+
/// No null terminating byte is added, it should be provided by the caller.
308+
fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
309+
Ok(Self(VecWrap(heapless::Vec::from_slice(v)?)))
310+
}
311+
}
312+
313+
impl<const N: usize> TryFrom<&str> for AsciiString<N> {
314+
type Error = ();
315+
316+
/// Convert from a `str`.
317+
///
318+
/// A null terminating byte is added.
319+
fn try_from(v: &str) -> Result<Self, Self::Error> {
320+
let mut h = heapless::Vec::from_slice(v.as_bytes())?;
321+
h.push(0x00).map_err(|_| ())?;
322+
Ok(Self(VecWrap(h)))
323+
}
324+
}
325+
326+
impl<'a, Predicate, const N: usize> DekuReader<'a, (Limit<u8, Predicate>, ())>
327+
for AsciiString<N>
328+
where
329+
Predicate: FnMut(&u8) -> bool,
330+
{
331+
fn from_reader_with_ctx<
332+
R: deku::no_std_io::Read + deku::no_std_io::Seek,
333+
>(
334+
reader: &mut deku::reader::Reader<R>,
335+
(limit, _ctx): (Limit<u8, Predicate>, ()),
336+
) -> core::result::Result<Self, DekuError> {
337+
let Limit::Count(count) = limit else {
338+
return Err(DekuError::Assertion(
339+
"Only count implemented for heapless::Vec".into(),
340+
));
341+
};
342+
343+
let mut v = heapless::Vec::new();
344+
for _ in 0..count {
345+
v.push(u8::from_reader_with_ctx(reader, ())?).map_err(|_| {
346+
DekuError::InvalidParam("Too many elements".into())
347+
})?
348+
}
349+
350+
Ok(AsciiString(VecWrap(v)))
351+
}
352+
}
353+
263354
#[derive(Debug, DekuRead, DekuWrite, PartialEq, Eq, Clone, Copy)]
264355
#[deku(endian = "little")]
265356
pub struct SensorId(pub u16);
@@ -659,17 +750,15 @@ pub struct FileDescriptorPdr {
659750
/// File name.
660751
///
661752
/// A null terminated string.
662-
// TODO: null terminated string type
663753
// TODO: max length
664754
#[deku(count = "file_name_len")]
665-
pub file_name: VecWrap<u8, MAX_PDR_TRANSFER>,
755+
pub file_name: AsciiString<MAX_PDR_TRANSFER>,
666756

667757
#[deku(temp, temp_value = "self.oem_file_name.len() as u8")]
668758
pub oem_file_name_len: u8,
669759
/// OEM file name.
670760
///
671-
/// A null terminated string.
672-
// TODO: null terminated string type
761+
/// A null terminated string. Must be empty if `oem_file_classification == 0`.
673762
#[deku(count = "oem_file_name_len")]
674-
pub oem_file_name: VecWrap<u8, MAX_PDR_TRANSFER>,
763+
pub oem_file_name: AsciiString<MAX_PDR_TRANSFER>,
675764
}

0 commit comments

Comments
 (0)