use super::*; use chrono::{NaiveDate, NaiveDateTime}; use hex::{FromHex, ToHex}; use std::mem::size_of; use yore::code_pages::CP437; /// The base trait for encoding. /// /// This trait is the working horse of the whole serialization: It takes a value /// and serializes/deserializes it. /// /// # Serialization /// /// The input is the value type, the output are bytes generated by a specific /// encoding. /// /// # Deserialization /// /// The input are bytes and the output is either an error or a tuple containing /// the deserialized value and the remaining data. pub trait Encoding { fn encode(input: &T) -> Vec; fn decode(bytes: &[u8]) -> ZVTResult<(T, &[u8])>; } /// Marker for Default encoding. /// /// This is for most cases the default encoding of the integral data types. pub struct Default; /// Macro for encoding integral types. macro_rules! encode_integral { ($ty:ty, $name:ident, $encode:ident, $decode:ident) => { impl Encoding<$ty> for $name { fn encode(input: &$ty) -> Vec { input.$encode().to_vec() } fn decode(data: &[u8]) -> ZVTResult<($ty, &[u8])> { let size = size_of::<$ty>(); if data.len() < size { Err(ZVTError::IncompleteData) } else { let bytes = data[0..size] .try_into() .map_err(|_| ZVTError::IncompleteData)?; let res = <$ty>::$decode(bytes); Ok((res, &data[size..])) } } } }; } // Register all unsigned integral data types. encode_integral!(u8, Default, to_le_bytes, from_le_bytes); encode_integral!(u16, Default, to_le_bytes, from_le_bytes); encode_integral!(u32, Default, to_le_bytes, from_le_bytes); encode_integral!(u64, Default, to_le_bytes, from_le_bytes); encode_integral!(usize, Default, to_le_bytes, from_le_bytes); /// Default encoding for [String]. /// /// The implementation of [decode] consumes the entire byte array. impl Encoding for Default { fn encode(input: &String) -> Vec { let res = CP437.encode(input).unwrap(); res.try_into().unwrap() } fn decode(data: &[u8]) -> ZVTResult<(String, &[u8])> { Ok(( CP437.decode(data).trim_end_matches(0u8 as char).to_string(), &[], )) } } /// Default encoding for [NaiveDateTime]. impl Encoding for Default { fn encode(_: &NaiveDateTime) -> Vec { vec![] } fn decode(mut data: &[u8]) -> ZVTResult<(NaiveDateTime, &[u8])> { let mut date = usize::default(); let mut time = u32::default(); let mut seen_tags = std::collections::HashSet::::new(); const DATE_TAG: u16 = 0x1f0e; const TIME_TAG: u16 = 0x1f0f; while !data.is_empty() { // Get the tag. let tag: Tag = Default::decode(data)?.0; match tag.0 { DATE_TAG => { if !seen_tags.insert(DATE_TAG) { return Err(ZVTError::DuplicateTag(Tag(DATE_TAG))); } // Get the date. (date, data) = >::deserialize_tagged( data, Some(Tag(DATE_TAG)) )?; } TIME_TAG => { if !seen_tags.insert(TIME_TAG) { return Err(ZVTError::DuplicateTag(Tag(TIME_TAG))); } (time, data) = >::deserialize_tagged( data, Some(Tag(TIME_TAG)), )?; } _ => break, } } // We haven't found everything we wanted. if seen_tags.len() != 2 { return Err(ZVTError::IncompleteData); } Ok(( NaiveDate::from_ymd_opt( date as i32 / 10000, (date as u32 % 1000) / 100, date as u32 % 100, ) .unwrap() .and_hms_opt(time / 10000, (time % 10000) / 100, time % 100) .ok_or(ZVTError::IncompleteData)?, data, )) } } /// Default encoding for [Tag]. /// /// The default is when the [Tag] is used as a Bmp-number or as a Tlv-tag. impl encoding::Encoding for Default { fn encode(input: &Tag) -> Vec { if (input.0 >> 8) == 0x1f { input.0.to_be_bytes().to_vec() } else { vec![input.0 as u8] } } fn decode(bytes: &[u8]) -> ZVTResult<(Tag, &[u8])> { let (tag, new_bytes): (u8, _) = encoding::BigEndian::decode(bytes)?; if tag == 0x1f { if bytes.len() < 2 { Err(ZVTError::IncompleteData) } else { let (tag, new_bytes): (u16, _) = encoding::BigEndian::decode(bytes)?; Ok((Tag(tag), new_bytes)) } } else { Ok((Tag(tag as u16), new_bytes)) } } } impl Encoding> for E where E: Encoding, { fn decode(data: &[u8]) -> ZVTResult<(Option, &[u8])> where Self: Sized, { match E::decode(data) { Err(err) => Err(err), Ok(data) => Ok((Some(data.0), data.1)), } } fn encode(input: &Option) -> Vec { match input { None => vec![], Some(inner) => E::encode(inner), } } } /// Blanket encoding/decoding for a [Vec]. /// /// The encoder will just encode every item and flatten the result. The decoder /// will decode the entire input into a [Vec]. impl Encoding> for E where E: Encoding, { fn encode(input: &Vec) -> Vec { input.iter().flat_map(|item| E::encode(item)).collect() } fn decode(mut bytes: &[u8]) -> ZVTResult<(Vec, &[u8])> { let mut out = Vec::new(); while !bytes.is_empty() { let (res, tmp) = E::decode(bytes)?; bytes = tmp; out.push(res); } Ok((out, bytes)) } } /// Marker for big endian encoding. /// /// Some formats (e.x. feig) require big endian encoding. The semantics are the /// same as in [Default]. pub struct BigEndian; // Register all unsigned integral data types. encode_integral!(u8, BigEndian, to_be_bytes, from_be_bytes); encode_integral!(u16, BigEndian, to_be_bytes, from_be_bytes); encode_integral!(u32, BigEndian, to_be_bytes, from_be_bytes); encode_integral!(u64, BigEndian, to_be_bytes, from_be_bytes); encode_integral!(usize, BigEndian, to_be_bytes, from_be_bytes); impl encoding::Encoding for BigEndian { fn encode(input: &Tag) -> Vec { encoding::BigEndian::encode(&input.0) } fn decode(bytes: &[u8]) -> ZVTResult<(Tag, &[u8])> { let res: (u16, _) = encoding::BigEndian::decode(bytes)?; Ok((Tag(res.0), res.1)) } } /// Marker for Bcd encoding. /// /// See https://en.wikipedia.org/wiki/Binary-coded_decimal for further details. /// /// The implementation of [decode] consumes the entire byte array. pub struct Bcd; macro_rules! bcd_integrals { ($ty:ty) => { impl Encoding<$ty> for Bcd { fn encode(input: &$ty) -> Vec { let mut k = *input; let mut rv = vec![]; while k != 0 { let mut curr = (k % 10) as u8; k /= 10; curr |= ((k % 10) as u8) << 4; k /= 10; rv.push(curr); } rv.reverse(); rv } fn decode(data: &[u8]) -> ZVTResult<($ty, &[u8])> { let mut rv = 0; for d in data.iter() { let high = (d >> 4) as $ty; let low = (d & 0xf) as $ty; if low != 0xf { rv = (rv * 100) + ((d >> 4) as $ty * 10) + low; } else { rv = (rv * 10) + high; } } Ok((rv, &[])) } } }; } bcd_integrals!(u8); bcd_integrals!(u16); bcd_integrals!(u32); bcd_integrals!(u64); bcd_integrals!(usize); pub struct Hex; impl Encoding for Hex { fn encode(input: &String) -> Vec { >::from_hex(input.clone().as_bytes()).unwrap() } fn decode(data: &[u8]) -> ZVTResult<(String, &[u8])> { Ok((data.encode_hex(), &[])) } } pub struct Utf8; impl Encoding for Utf8 { fn encode(_: &String) -> Vec { vec![] } fn decode(data: &[u8]) -> ZVTResult<(String, &[u8])> { let string = String::from_utf8(data.to_vec()).map_err(|_| ZVTError::IncompleteData)?; Ok((string, &[])) } } /// Macro for registering the basic types defined here as a ZvtSerializerImpl /// trait. macro_rules! zvt_serializer_registry { ($ty:ty) => { impl, TE: encoding::Encoding> ZvtSerializerImpl for $ty { } }; } zvt_serializer_registry!(u8); zvt_serializer_registry!(u16); zvt_serializer_registry!(u32); zvt_serializer_registry!(u64); zvt_serializer_registry!(usize); zvt_serializer_registry!(String); zvt_serializer_registry!(NaiveDateTime); #[cfg(test)] mod test { use super::*; #[test] fn test_default() { // Simple encoding. assert_eq!(Default::encode(&1234u16), [210, 4]); assert_eq!(Default::encode(&1234u32), [210, 4, 0, 0]); assert_eq!(Default::encode(&1234u64), [210, 4, 0, 0, 0, 0, 0, 0]); // Simple decoding. let a: u16 = Default::decode(&[210, 4]).unwrap().0; assert_eq!(a, 1234); let a: u32 = Default::decode(&[210, 4, 0, 0]).unwrap().0; assert_eq!(a, 1234); let a: u64 = Default::decode(&[210, 4, 0, 0, 0, 0, 0, 0]).unwrap().0; assert_eq!(a, 1234); // Errors let a: ZVTResult<(u16, _)> = Default::decode(&[1]); assert_eq!(a, Err(ZVTError::IncompleteData)); } #[test] fn test_big_endian() { assert_eq!(BigEndian::encode(&1234u16), [4, 210]); assert_eq!(BigEndian::encode(&1234u32), [0, 0, 4, 210]); assert_eq!(BigEndian::encode(&1234u64), [0, 0, 0, 0, 0, 0, 4, 210]); let a: u16 = BigEndian::decode(&[4, 210]).unwrap().0; assert_eq!(a, 1234); let a: u32 = BigEndian::decode(&[0, 0, 4, 210]).unwrap().0; assert_eq!(a, 1234); let a: u64 = BigEndian::decode(&[0, 0, 0, 0, 0, 0, 4, 210]).unwrap().0; assert_eq!(a, 1234); let a: ZVTResult<(u32, _)> = BigEndian::decode(&[1, 2, 3]); assert_eq!(a, Err(ZVTError::IncompleteData)); } #[test] fn test_bcd() { assert_eq!(Bcd::encode(&1234u16), [0x12, 0x34]); let a: u16 = Bcd::decode(&[0x12, 0x34]).unwrap().0; assert_eq!(a, 1234); } }