zvt_builder/
encoding.rs

1use super::*;
2use chrono::{NaiveDate, NaiveDateTime};
3use hex::{FromHex, ToHex};
4use std::mem::size_of;
5use yore::code_pages::CP437;
6
7/// The base trait for encoding.
8///
9/// This trait is the working horse of the whole serialization: It takes a value
10/// and serializes/deserializes it.
11///
12/// # Serialization
13///
14/// The input is the value type, the output are bytes generated by a specific
15/// encoding.
16///
17/// # Deserialization
18///
19/// The input are bytes and the output is either an error or a tuple containing
20/// the deserialized value and the remaining data.
21pub trait Encoding<T> {
22    fn encode(input: &T) -> Vec<u8>;
23    fn decode(bytes: &[u8]) -> ZVTResult<(T, &[u8])>;
24}
25
26/// Marker for Default encoding.
27///
28/// This is for most cases the default encoding of the integral data types.
29pub struct Default;
30
31/// Macro for encoding integral types.
32macro_rules! encode_integral {
33    ($ty:ty, $name:ident, $encode:ident, $decode:ident) => {
34        impl Encoding<$ty> for $name {
35            fn encode(input: &$ty) -> Vec<u8> {
36                input.$encode().to_vec()
37            }
38
39            fn decode(data: &[u8]) -> ZVTResult<($ty, &[u8])> {
40                let size = size_of::<$ty>();
41
42                if data.len() < size {
43                    Err(ZVTError::IncompleteData)
44                } else {
45                    let bytes = data[0..size]
46                        .try_into()
47                        .map_err(|_| ZVTError::IncompleteData)?;
48                    let res = <$ty>::$decode(bytes);
49                    Ok((res, &data[size..]))
50                }
51            }
52        }
53    };
54}
55
56// Register all unsigned integral data types.
57encode_integral!(u8, Default, to_le_bytes, from_le_bytes);
58encode_integral!(u16, Default, to_le_bytes, from_le_bytes);
59encode_integral!(u32, Default, to_le_bytes, from_le_bytes);
60encode_integral!(u64, Default, to_le_bytes, from_le_bytes);
61encode_integral!(usize, Default, to_le_bytes, from_le_bytes);
62
63/// Default encoding for [String].
64///
65/// The implementation of [decode] consumes the entire byte array.
66impl Encoding<String> for Default {
67    fn encode(input: &String) -> Vec<u8> {
68        let res = CP437.encode(input).unwrap();
69        res.try_into().unwrap()
70    }
71
72    fn decode(data: &[u8]) -> ZVTResult<(String, &[u8])> {
73        Ok((
74            CP437.decode(data).trim_end_matches(0u8 as char).to_string(),
75            &[],
76        ))
77    }
78}
79
80/// Default encoding for [NaiveDateTime].
81impl Encoding<NaiveDateTime> for Default {
82    fn encode(_: &NaiveDateTime) -> Vec<u8> {
83        vec![]
84    }
85
86    fn decode(mut data: &[u8]) -> ZVTResult<(NaiveDateTime, &[u8])> {
87        let mut date = usize::default();
88        let mut time = u32::default();
89        let mut seen_tags = std::collections::HashSet::<u16>::new();
90        const DATE_TAG: u16 = 0x1f0e;
91        const TIME_TAG: u16 = 0x1f0f;
92        while !data.is_empty() {
93            // Get the tag.
94            let tag: Tag = Default::decode(data)?.0;
95            match tag.0 {
96                DATE_TAG => {
97                    if !seen_tags.insert(DATE_TAG) {
98                        return Err(ZVTError::DuplicateTag(Tag(DATE_TAG)));
99                    }
100                    // Get the date.
101                    (date, data) = <usize as ZvtSerializerImpl<
102                        length::Tlv,
103                        encoding::Bcd,
104                    >>::deserialize_tagged(
105                        data, Some(Tag(DATE_TAG))
106                    )?;
107                }
108                TIME_TAG => {
109                    if !seen_tags.insert(TIME_TAG) {
110                        return Err(ZVTError::DuplicateTag(Tag(TIME_TAG)));
111                    }
112                    (time, data) =
113                        <u32 as ZvtSerializerImpl<length::Tlv, encoding::Bcd>>::deserialize_tagged(
114                            data,
115                            Some(Tag(TIME_TAG)),
116                        )?;
117                }
118                _ => break,
119            }
120        }
121        // We haven't found everything we wanted.
122        if seen_tags.len() != 2 {
123            return Err(ZVTError::IncompleteData);
124        }
125
126        Ok((
127            NaiveDate::from_ymd_opt(
128                date as i32 / 10000,
129                (date as u32 % 1000) / 100,
130                date as u32 % 100,
131            )
132            .unwrap()
133            .and_hms_opt(time / 10000, (time % 10000) / 100, time % 100)
134            .ok_or(ZVTError::IncompleteData)?,
135            data,
136        ))
137    }
138}
139
140/// Default encoding for [Tag].
141///
142/// The default is when the [Tag] is used as a Bmp-number or as a Tlv-tag.
143impl encoding::Encoding<Tag> for Default {
144    fn encode(input: &Tag) -> Vec<u8> {
145        if (input.0 >> 8) == 0x1f {
146            input.0.to_be_bytes().to_vec()
147        } else {
148            vec![input.0 as u8]
149        }
150    }
151
152    fn decode(bytes: &[u8]) -> ZVTResult<(Tag, &[u8])> {
153        let (tag, new_bytes): (u8, _) = encoding::BigEndian::decode(bytes)?;
154        if tag == 0x1f {
155            if bytes.len() < 2 {
156                Err(ZVTError::IncompleteData)
157            } else {
158                let (tag, new_bytes): (u16, _) = encoding::BigEndian::decode(bytes)?;
159                Ok((Tag(tag), new_bytes))
160            }
161        } else {
162            Ok((Tag(tag as u16), new_bytes))
163        }
164    }
165}
166
167impl<T, E> Encoding<Option<T>> for E
168where
169    E: Encoding<T>,
170{
171    fn decode(data: &[u8]) -> ZVTResult<(Option<T>, &[u8])>
172    where
173        Self: Sized,
174    {
175        match E::decode(data) {
176            Err(err) => Err(err),
177            Ok(data) => Ok((Some(data.0), data.1)),
178        }
179    }
180
181    fn encode(input: &Option<T>) -> Vec<u8> {
182        match input {
183            None => vec![],
184            Some(inner) => E::encode(inner),
185        }
186    }
187}
188
189/// Blanket encoding/decoding for a [Vec].
190///
191/// The encoder will just encode every item and flatten the result. The decoder
192/// will decode the entire input into a [Vec].
193impl<T, E> Encoding<Vec<T>> for E
194where
195    E: Encoding<T>,
196{
197    fn encode(input: &Vec<T>) -> Vec<u8> {
198        input.iter().flat_map(|item| E::encode(item)).collect()
199    }
200
201    fn decode(mut bytes: &[u8]) -> ZVTResult<(Vec<T>, &[u8])> {
202        let mut out = Vec::new();
203        while !bytes.is_empty() {
204            let (res, tmp) = E::decode(bytes)?;
205            bytes = tmp;
206            out.push(res);
207        }
208        Ok((out, bytes))
209    }
210}
211
212/// Marker for big endian encoding.
213///
214/// Some formats (e.x. feig) require big endian encoding. The semantics are the
215/// same as in [Default].
216pub struct BigEndian;
217
218// Register all unsigned integral data types.
219encode_integral!(u8, BigEndian, to_be_bytes, from_be_bytes);
220encode_integral!(u16, BigEndian, to_be_bytes, from_be_bytes);
221encode_integral!(u32, BigEndian, to_be_bytes, from_be_bytes);
222encode_integral!(u64, BigEndian, to_be_bytes, from_be_bytes);
223encode_integral!(usize, BigEndian, to_be_bytes, from_be_bytes);
224
225impl encoding::Encoding<Tag> for BigEndian {
226    fn encode(input: &Tag) -> Vec<u8> {
227        encoding::BigEndian::encode(&input.0)
228    }
229
230    fn decode(bytes: &[u8]) -> ZVTResult<(Tag, &[u8])> {
231        let res: (u16, _) = encoding::BigEndian::decode(bytes)?;
232        Ok((Tag(res.0), res.1))
233    }
234}
235
236/// Marker for Bcd encoding.
237///
238/// See https://en.wikipedia.org/wiki/Binary-coded_decimal for further details.
239///
240/// The implementation of [decode] consumes the entire byte array.
241pub struct Bcd;
242
243macro_rules! bcd_integrals {
244    ($ty:ty) => {
245        impl Encoding<$ty> for Bcd {
246            fn encode(input: &$ty) -> Vec<u8> {
247                let mut k = *input;
248                let mut rv = vec![];
249                while k != 0 {
250                    let mut curr = (k % 10) as u8;
251                    k /= 10;
252                    curr |= ((k % 10) as u8) << 4;
253                    k /= 10;
254                    rv.push(curr);
255                }
256                rv.reverse();
257                rv
258            }
259
260            fn decode(data: &[u8]) -> ZVTResult<($ty, &[u8])> {
261                let mut rv = 0;
262                for d in data.iter() {
263                    let high = (d >> 4) as $ty;
264                    let low = (d & 0xf) as $ty;
265                    if low != 0xf {
266                        rv = (rv * 100) + ((d >> 4) as $ty * 10) + low;
267                    } else {
268                        rv = (rv * 10) + high;
269                    }
270                }
271                Ok((rv, &[]))
272            }
273        }
274    };
275}
276
277bcd_integrals!(u8);
278bcd_integrals!(u16);
279bcd_integrals!(u32);
280bcd_integrals!(u64);
281bcd_integrals!(usize);
282
283pub struct Hex;
284
285impl Encoding<String> for Hex {
286    fn encode(input: &String) -> Vec<u8> {
287        <Vec<u8>>::from_hex(input.clone().as_bytes()).unwrap()
288    }
289
290    fn decode(data: &[u8]) -> ZVTResult<(String, &[u8])> {
291        Ok((data.encode_hex(), &[]))
292    }
293}
294
295pub struct Utf8;
296
297impl Encoding<String> for Utf8 {
298    fn encode(_: &String) -> Vec<u8> {
299        vec![]
300    }
301
302    fn decode(data: &[u8]) -> ZVTResult<(String, &[u8])> {
303        let string = String::from_utf8(data.to_vec()).map_err(|_| ZVTError::IncompleteData)?;
304        Ok((string, &[]))
305    }
306}
307
308/// Macro for registering the basic types defined here as a ZvtSerializerImpl
309/// trait.
310macro_rules! zvt_serializer_registry {
311    ($ty:ty) => {
312        impl<L: length::Length, E: encoding::Encoding<$ty>, TE: encoding::Encoding<Tag>>
313            ZvtSerializerImpl<L, E, TE> for $ty
314        {
315        }
316    };
317}
318
319zvt_serializer_registry!(u8);
320zvt_serializer_registry!(u16);
321zvt_serializer_registry!(u32);
322zvt_serializer_registry!(u64);
323zvt_serializer_registry!(usize);
324zvt_serializer_registry!(String);
325zvt_serializer_registry!(NaiveDateTime);
326
327#[cfg(test)]
328mod test {
329    use super::*;
330
331    #[test]
332    fn test_default() {
333        // Simple encoding.
334        assert_eq!(Default::encode(&1234u16), [210, 4]);
335        assert_eq!(Default::encode(&1234u32), [210, 4, 0, 0]);
336        assert_eq!(Default::encode(&1234u64), [210, 4, 0, 0, 0, 0, 0, 0]);
337
338        // Simple decoding.
339        let a: u16 = Default::decode(&[210, 4]).unwrap().0;
340        assert_eq!(a, 1234);
341        let a: u32 = Default::decode(&[210, 4, 0, 0]).unwrap().0;
342        assert_eq!(a, 1234);
343
344        let a: u64 = Default::decode(&[210, 4, 0, 0, 0, 0, 0, 0]).unwrap().0;
345        assert_eq!(a, 1234);
346
347        // Errors
348        let a: ZVTResult<(u16, _)> = Default::decode(&[1]);
349        assert_eq!(a, Err(ZVTError::IncompleteData));
350    }
351
352    #[test]
353    fn test_big_endian() {
354        assert_eq!(BigEndian::encode(&1234u16), [4, 210]);
355        assert_eq!(BigEndian::encode(&1234u32), [0, 0, 4, 210]);
356        assert_eq!(BigEndian::encode(&1234u64), [0, 0, 0, 0, 0, 0, 4, 210]);
357
358        let a: u16 = BigEndian::decode(&[4, 210]).unwrap().0;
359        assert_eq!(a, 1234);
360        let a: u32 = BigEndian::decode(&[0, 0, 4, 210]).unwrap().0;
361        assert_eq!(a, 1234);
362
363        let a: u64 = BigEndian::decode(&[0, 0, 0, 0, 0, 0, 4, 210]).unwrap().0;
364        assert_eq!(a, 1234);
365
366        let a: ZVTResult<(u32, _)> = BigEndian::decode(&[1, 2, 3]);
367        assert_eq!(a, Err(ZVTError::IncompleteData));
368    }
369
370    #[test]
371    fn test_bcd() {
372        assert_eq!(Bcd::encode(&1234u16), [0x12, 0x34]);
373        let a: u16 = Bcd::decode(&[0x12, 0x34]).unwrap().0;
374        assert_eq!(a, 1234);
375    }
376}