Skip to main content

ember_plus/ber/
writer.rs

1//! BER writer for encoding data to BER format.
2
3use super::{Tag, Length, TagClass, TagType};
4use crate::error::Result;
5
6/// A writer for BER-encoded data.
7#[derive(Debug, Default)]
8pub struct BerWriter {
9    buffer: Vec<u8>,
10}
11
12impl BerWriter {
13    /// Create a new BER writer.
14    pub fn new() -> Self {
15        BerWriter { buffer: Vec::new() }
16    }
17
18    /// Create a new BER writer with initial capacity.
19    pub fn with_capacity(capacity: usize) -> Self {
20        BerWriter { buffer: Vec::with_capacity(capacity) }
21    }
22
23    /// Get the written bytes.
24    pub fn as_bytes(&self) -> &[u8] {
25        &self.buffer
26    }
27
28    /// Consume the writer and return the bytes.
29    pub fn into_bytes(self) -> Vec<u8> {
30        self.buffer
31    }
32
33    /// Get the current length.
34    pub fn len(&self) -> usize {
35        self.buffer.len()
36    }
37
38    /// Check if the buffer is empty.
39    pub fn is_empty(&self) -> bool {
40        self.buffer.is_empty()
41    }
42
43    /// Write raw bytes.
44    pub fn write_raw(&mut self, bytes: &[u8]) {
45        self.buffer.extend_from_slice(bytes);
46    }
47
48    /// Write a tag.
49    pub fn write_tag(&mut self, tag: &Tag) {
50        self.buffer.extend(tag.encode());
51    }
52
53    /// Write a length.
54    pub fn write_length(&mut self, length: &Length) {
55        self.buffer.extend(length.encode());
56    }
57
58    /// Write a TLV with the given tag and value.
59    pub fn write_tlv(&mut self, tag: &Tag, value: &[u8]) {
60        self.write_tag(tag);
61        self.write_length(&Length::Definite(value.len()));
62        self.write_raw(value);
63    }
64
65    /// Write a boolean value.
66    pub fn write_boolean(&mut self, value: bool) -> Result<()> {
67        self.write_tlv(&Tag::BOOLEAN, &[if value { 0xFF } else { 0x00 }]);
68        Ok(())
69    }
70
71    /// Write an integer value.
72    pub fn write_integer(&mut self, value: i64) -> Result<()> {
73        let bytes = Self::encode_integer(value);
74        self.write_tlv(&Tag::INTEGER, &bytes);
75        Ok(())
76    }
77
78    /// Write an integer with a context tag.
79    pub fn write_context_integer(&mut self, tag_number: u32, value: i64) -> Result<()> {
80        let tag = Tag::new(TagClass::Context, TagType::Primitive, tag_number);
81        let bytes = Self::encode_integer(value);
82        self.write_tlv(&tag, &bytes);
83        Ok(())
84    }
85
86    /// Encode an integer to bytes.
87    fn encode_integer(value: i64) -> Vec<u8> {
88        if value == 0 {
89            return vec![0];
90        }
91
92        let mut bytes = Vec::new();
93        let mut remaining = value;
94        
95        // Handle both positive and negative numbers
96        if value > 0 {
97            while remaining > 0 {
98                bytes.push((remaining & 0xFF) as u8);
99                remaining >>= 8;
100            }
101            // Add leading zero if high bit is set (would look negative)
102            if !bytes.is_empty() && (bytes.last().unwrap() & 0x80) != 0 {
103                bytes.push(0);
104            }
105        } else {
106            // Negative numbers
107            while remaining != -1 || bytes.is_empty() || (bytes.last().unwrap() & 0x80) == 0 {
108                bytes.push((remaining & 0xFF) as u8);
109                remaining >>= 8;
110                if bytes.len() >= 8 {
111                    break;
112                }
113            }
114        }
115        
116        bytes.reverse();
117        bytes
118    }
119
120    /// Write a real (floating point) value.
121    pub fn write_real(&mut self, value: f64) -> Result<()> {
122        let bytes = Self::encode_real(value);
123        self.write_tlv(&Tag::REAL, &bytes);
124        Ok(())
125    }
126
127    /// Encode a real to bytes.
128    fn encode_real(value: f64) -> Vec<u8> {
129        if value == 0.0 {
130            if value.is_sign_negative() {
131                return vec![0x43]; // Minus zero
132            }
133            return vec![]; // Plus zero
134        }
135        
136        if value.is_infinite() {
137            return if value.is_sign_positive() {
138                vec![0x40] // Plus infinity
139            } else {
140                vec![0x41] // Minus infinity
141            };
142        }
143        
144        if value.is_nan() {
145            return vec![0x42]; // NaN
146        }
147        
148        // Use IEEE 754 double-precision encoding
149        let bits = value.to_bits();
150        let sign = (bits >> 63) as u8;
151        let exponent = ((bits >> 52) & 0x7FF) as i16 - 1023 - 52;
152        let mantissa = if ((bits >> 52) & 0x7FF) == 0 {
153            bits & 0xFFFFFFFFFFFFF // Denormalized
154        } else {
155            (bits & 0xFFFFFFFFFFFFF) | 0x10000000000000 // Add implicit bit
156        };
157        
158        // Remove trailing zeros from mantissa
159        let mut m = mantissa;
160        let mut exp = exponent;
161        while m != 0 && (m & 1) == 0 {
162            m >>= 1;
163            exp += 1;
164        }
165        
166        // Encode mantissa bytes
167        let mut mantissa_bytes = Vec::new();
168        let mut temp = m;
169        while temp > 0 {
170            mantissa_bytes.push((temp & 0xFF) as u8);
171            temp >>= 8;
172        }
173        mantissa_bytes.reverse();
174        
175        // Encode exponent bytes
176        let exp_bytes = Self::encode_integer(exp as i64);
177        
178        // Build result
179        let mut result = Vec::new();
180        
181        // First byte: binary encoding, base 2, scale 0
182        let mut first_byte: u8 = 0x80; // Binary encoding
183        if sign != 0 {
184            first_byte |= 0x40; // Negative
185        }
186        
187        match exp_bytes.len() {
188            1 => first_byte |= 0x00,
189            2 => first_byte |= 0x01,
190            3 => first_byte |= 0x02,
191            _ => first_byte |= 0x03,
192        }
193        
194        result.push(first_byte);
195        
196        if exp_bytes.len() > 3 {
197            result.push(exp_bytes.len() as u8);
198        }
199        
200        result.extend(&exp_bytes);
201        result.extend(&mantissa_bytes);
202        
203        result
204    }
205
206    /// Write a UTF-8 string.
207    pub fn write_utf8_string(&mut self, value: &str) -> Result<()> {
208        self.write_tlv(&Tag::UTF8_STRING, value.as_bytes());
209        Ok(())
210    }
211
212    /// Write an octet string.
213    pub fn write_octet_string(&mut self, value: &[u8]) -> Result<()> {
214        self.write_tlv(&Tag::OCTET_STRING, value);
215        Ok(())
216    }
217
218    /// Write a null value.
219    pub fn write_null(&mut self) -> Result<()> {
220        self.write_tlv(&Tag::NULL, &[]);
221        Ok(())
222    }
223
224    /// Write a sequence.
225    pub fn write_sequence<F>(&mut self, f: F) -> Result<()>
226    where
227        F: FnOnce(&mut BerWriter) -> Result<()>,
228    {
229        let mut inner = BerWriter::new();
230        f(&mut inner)?;
231        self.write_tlv(&Tag::SEQUENCE, inner.as_bytes());
232        Ok(())
233    }
234
235    /// Write a set.
236    pub fn write_set<F>(&mut self, f: F) -> Result<()>
237    where
238        F: FnOnce(&mut BerWriter) -> Result<()>,
239    {
240        let mut inner = BerWriter::new();
241        f(&mut inner)?;
242        self.write_tlv(&Tag::SET, inner.as_bytes());
243        Ok(())
244    }
245
246    /// Write a UTF8String.
247    pub fn write_utf8string(&mut self, value: &str) {
248        self.write_tlv(&Tag::UTF8_STRING, value.as_bytes());
249    }
250
251    /// Write a context-tagged constructed value.
252    pub fn write_context<F>(&mut self, tag_number: u32, f: F) -> Result<()>
253    where
254        F: FnOnce(&mut BerWriter) -> Result<()>,
255    {
256        let tag = Tag::context_constructed(tag_number);
257        let mut inner = BerWriter::new();
258        f(&mut inner)?;
259        self.write_tlv(&tag, inner.as_bytes());
260        Ok(())
261    }
262
263    /// Write a context-tagged primitive value.
264    pub fn write_context_primitive(&mut self, tag_number: u32, value: &[u8]) -> Result<()> {
265        let tag = Tag::context_primitive(tag_number);
266        self.write_tlv(&tag, value);
267        Ok(())
268    }
269
270    /// Write an application-tagged constructed value.
271    pub fn write_application<F>(&mut self, tag_number: u32, f: F) -> Result<()>
272    where
273        F: FnOnce(&mut BerWriter) -> Result<()>,
274    {
275        let tag = Tag::application_constructed(tag_number);
276        let mut inner = BerWriter::new();
277        f(&mut inner)?;
278        self.write_tlv(&tag, inner.as_bytes());
279        Ok(())
280    }
281
282    /// Write an application-tagged primitive value.
283    pub fn write_application_primitive(&mut self, tag_number: u32, value: &[u8]) -> Result<()> {
284        let tag = Tag::application_primitive(tag_number);
285        self.write_tlv(&tag, value);
286        Ok(())
287    }
288
289    /// Write a relative OID.
290    pub fn write_relative_oid(&mut self, components: &[u32]) -> Result<()> {
291        let mut bytes = Vec::new();
292        
293        for &component in components {
294            let mut temp = Vec::new();
295            let mut value = component;
296            
297            temp.push((value & 0x7F) as u8);
298            value >>= 7;
299            
300            while value > 0 {
301                temp.push(((value & 0x7F) | 0x80) as u8);
302                value >>= 7;
303            }
304            
305            temp.reverse();
306            bytes.extend(temp);
307        }
308        
309        self.write_tlv(&Tag::RELATIVE_OID, &bytes);
310        Ok(())
311    }
312}
313
314#[cfg(test)]
315mod tests {
316    use super::*;
317
318    #[test]
319    fn test_integer_encoding() {
320        // Test cases: (value, expected_bytes)
321        let cases = [
322            (0i64, vec![0x00]),
323            (1, vec![0x01]),
324            (127, vec![0x7F]),
325            (128, vec![0x00, 0x80]),
326            (256, vec![0x01, 0x00]),
327            (-1, vec![0xFF]),
328            (-128, vec![0x80]),
329            (-129, vec![0xFF, 0x7F]),
330        ];
331        
332        for (value, expected) in cases {
333            let encoded = BerWriter::encode_integer(value);
334            assert_eq!(encoded, expected, "failed for value {}", value);
335        }
336    }
337}