use core::fmt::{self, Write as _}; use nom::{ bytes::complete::{tag, take_until}, combinator::rest, error::context, multi::{length_value, many0}, number::{complete::le_u32 as le_u32_complete, streaming::le_u32 as le_u32_streaming}, sequence::separated_pair, Parser, }; use smallvec::SmallVec; use super::{fields, IResult, Input, Op}; use crate::{Error, Result}; #[derive(Clone, Debug)] pub struct HeaderField { name: SmallVec<[u8; 16]>, value: SmallVec<[u8; 16]>, } impl HeaderField { pub fn name(&self) -> &[u8] { &self.name } pub fn value(&self) -> &[u8] { &self.value } pub fn parse(input: Input) -> IResult { // Uses complete combinators because Header has length context( "Header Entry", length_value( le_u32_complete, separated_pair(take_until("="), tag("="), rest), ), ) .map(|(name, value)| HeaderField { name: SmallVec::from_slice(name), value: SmallVec::from_slice(value), }) .parse(input) } } impl fmt::Display for HeaderField { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let name = String::from_utf8_lossy(self.name.as_ref()); write!(f, "{}=", name)?; for byte in self.value.iter().copied() { write!(f, "{:02x} ", byte)?; } Ok(()) } } #[derive(Clone, Debug)] pub struct Header(pub Vec); impl Header { pub fn parse(input: Input) -> IResult { context( "Header", length_value(le_u32_streaming, many0(HeaderField::parse)), ) .map(Header) .parse(input) } pub fn find_field(&self, name: &[u8]) -> Result<&[u8]> { self.0 .iter() .find(|field| field.name() == name) .map(|field| field.value()) .ok_or_else(|| Error::MissingField(String::from_utf8_lossy(name).into_owned())) } pub fn read_op(&self) -> Result { self.find_field(b"op").and_then(fields::Op::parse) } pub fn read_u64(&self, field: &[u8]) -> Result { self.find_field(field).and_then(fields::parse_u64) } pub fn read_u32(&self, field: &[u8]) -> Result { self.find_field(field).and_then(fields::parse_u32) } pub fn read_string(&self, field: &[u8]) -> Result { self.find_field(field).and_then(fields::parse_string) } } impl fmt::Display for Header { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut first = true; for header in &self.0 { if first { first = false; } else { f.write_char('\n')?; } header.fmt(f)?; } Ok(()) } }