asn1_rs/to_ber/
encoder.rs

1use std::io::{self, Write};
2
3use crate::{Class, Length, Tag};
4
5/// Common trait for BER encoders
6///
7/// A BER encoder is an object used to encode the header (full tag including
8/// constructed and class) and length
9pub trait BerEncoder {
10    /// Build a new encoder
11    fn new() -> Self;
12
13    /// Write tag, constructed bit, and class to `target`
14    // NOTE: mut is here to allow keeping state
15    fn write_tag_info<W: Write>(
16        &mut self,
17        class: Class,
18        constructed: bool,
19        tag: Tag,
20        target: &mut W,
21    ) -> Result<usize, io::Error> {
22        self.write_tag_generic(class, constructed, tag, target)
23    }
24
25    /// This functions writes a full tag (Class, Constructed and Number) to `target`
26    ///
27    /// Note: this function should not be reimplemented unless implementer has very good reasons!
28    fn write_tag_generic<W: Write>(
29        &mut self,
30        class: Class,
31        constructed: bool,
32        tag: Tag,
33        target: &mut W,
34    ) -> Result<usize, io::Error> {
35        let class = class as u8;
36
37        const CONSTRUCTED_BIT: u8 = 0b0010_0000;
38        let cs = if constructed { CONSTRUCTED_BIT } else { 0 };
39
40        // write tag
41        if tag.0 < 31 {
42            // tag is primitive, and uses one byte
43            let b0 = (class << 6) | cs | (tag.0 as u8);
44            target.write(&[b0])
45        } else {
46            // tag number must be encoded in long form
47
48            // first byte
49            let b0 = (class << 6) | cs | 0b1_1111;
50            let mut sz = target.write(&[b0])?;
51
52            // now write bytes from right (last) to left
53            let mut val = tag.0;
54
55            const BUF_SZ: usize = 8;
56            let mut buffer = [0u8; BUF_SZ];
57            let mut current_index = BUF_SZ - 1;
58
59            // last encoded byte
60            buffer[current_index] = (val & 0x7f) as u8;
61            val >>= 7;
62
63            while val > 0 {
64                current_index -= 1;
65                if current_index == 0 {
66                    // return Err(SerializeError::InvalidLength);
67                    return Err(io::Error::new(io::ErrorKind::InvalidData, "tag too long"));
68                }
69                buffer[current_index] = (val & 0x7f) as u8 | 0x80;
70                val >>= 7;
71            }
72
73            sz += target.write(&buffer[current_index..])?;
74            Ok(sz)
75        }
76    }
77
78    /// Write the length of the encoded object content (without header) to `target`
79    fn write_length<W: Write>(
80        &mut self,
81        length: Length,
82        target: &mut W,
83    ) -> Result<usize, io::Error> {
84        const INDEFINITE: u8 = 0b1000_0000;
85        match length {
86            Length::Indefinite => target.write(&[INDEFINITE]),
87            Length::Definite(n) => {
88                if n <= 127 {
89                    // short form
90                    target.write(&[n as u8])
91                } else {
92                    // long form
93                    let b = n.to_be_bytes();
94                    // skip leading zeroes
95                    // we do not have to test for length, l cannot be 0
96                    let mut idx = 0;
97                    while b[idx] == 0 {
98                        idx += 1;
99                    }
100                    let b = &b[idx..];
101                    // first byte: 0x80 + length of length
102                    let b0 = 0x80 | (b.len() as u8);
103                    let sz = target.write(&[b0])?;
104                    let sz = sz + target.write(b)?;
105                    Ok(sz)
106                }
107            }
108        }
109    }
110}
111
112#[cfg(test)]
113mod tests {
114    use hex_literal::hex;
115
116    use crate::{BerEncoder, Length, Primitive};
117
118    #[test]
119    fn tober_write_length() {
120        let mut encoder = Primitive::<0>::new();
121        let mut v: Vec<u8> = Vec::new();
122
123        // test: Indefinite length
124        v.clear();
125        encoder
126            .write_length(Length::Indefinite, &mut v)
127            .expect("serialization failed");
128        assert_eq!(&v, &hex!("80"));
129
130        // test: definite length, short-form
131        v.clear();
132        encoder
133            .write_length(Length::Definite(2), &mut v)
134            .expect("serialization failed");
135        assert_eq!(&v, &hex!("02"));
136
137        // test: definite length, long-form
138        v.clear();
139        encoder
140            .write_length(Length::Definite(300), &mut v)
141            .expect("serialization failed");
142        assert_eq!(&v, &hex!("82 01 2c"));
143    }
144}