use deku::DekuContainerRead;
#[cfg(debug_assertions)]
use deku::DekuContainerWrite;
use super::Ie;
pub fn from_bytes(bytes: &[u8]) -> Vec<Ie> {
let mut ies = Vec::new();
let mut input = bytes;
while !input.is_empty() {
let offset = bytes.len() - input.len();
match Ie::from_bytes((input, 0)) {
Ok(((rest, _), ie)) => {
let bytes_read = input.len() - rest.len();
let expected_bytes = usize::from(ie.len) + 2;
if bytes_read != expected_bytes {
tracing::warn!(
"Incorrect number of bytes read for IE at offset {}: read {}, expected {}. IE: {:?}",
offset,
bytes_read,
expected_bytes,
&ie
);
}
#[cfg(debug_assertions)]
if let Ok(serialized) = ie.to_bytes()
&& serialized.as_slice() != &input[..expected_bytes.min(input.len())]
{
tracing::warn!(
"Mismatch between raw IE bytes and parsed Ie::to_bytes at offset {}. IE: {:?}",
offset,
&ie
);
}
ies.push(ie);
if expected_bytes > input.len() {
tracing::warn!(
"IE at offset {} declares {} bytes but only {} bytes remain",
offset,
expected_bytes,
input.len()
);
break;
}
input = &input[expected_bytes..];
}
Err(error) => {
let failed_bytes = bytes
.get(offset..offset.saturating_add(20).min(bytes.len()))
.unwrap_or(&[]);
tracing::warn!(
"Failed to parse IE at offset {} (parsed {} IEs successfully): {:?}. Failed bytes: {:02x?}",
offset,
ies.len(),
error,
failed_bytes
);
break;
}
}
}
ies
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_bytes_stops_on_truncated_ie() {
let ies = from_bytes(&[0x00, 0x05, b'H', b'i']);
assert!(ies.is_empty());
}
}