Skip to main content

ember_plus/ber/
value.rs

1//! BER value types.
2
3use super::{Tag, BerReader, BerWriter};
4use crate::error::Result;
5
6/// A generic BER value that can hold any type.
7#[derive(Debug, Clone, PartialEq)]
8pub enum BerValue {
9    /// Boolean value
10    Boolean(bool),
11    /// Integer value
12    Integer(i64),
13    /// Real (floating point) value
14    Real(f64),
15    /// UTF-8 string value
16    String(String),
17    /// Octet string (raw bytes) value
18    OctetString(Vec<u8>),
19    /// Null value
20    Null,
21    /// Sequence of values
22    Sequence(Vec<BerValue>),
23    /// Context-tagged value
24    Context { tag: u32, value: Box<BerValue> },
25    /// Application-tagged value
26    Application { tag: u32, value: Box<BerValue> },
27    /// Raw TLV (for unknown or unprocessed data)
28    Raw { tag: Tag, data: Vec<u8> },
29}
30
31impl BerValue {
32    /// Try to get this value as a boolean.
33    pub fn as_boolean(&self) -> Option<bool> {
34        match self {
35            BerValue::Boolean(v) => Some(*v),
36            _ => None,
37        }
38    }
39
40    /// Try to get this value as an integer.
41    pub fn as_integer(&self) -> Option<i64> {
42        match self {
43            BerValue::Integer(v) => Some(*v),
44            _ => None,
45        }
46    }
47
48    /// Try to get this value as a real.
49    pub fn as_real(&self) -> Option<f64> {
50        match self {
51            BerValue::Real(v) => Some(*v),
52            BerValue::Integer(v) => Some(*v as f64),
53            _ => None,
54        }
55    }
56
57    /// Try to get this value as a string.
58    pub fn as_string(&self) -> Option<&str> {
59        match self {
60            BerValue::String(v) => Some(v),
61            _ => None,
62        }
63    }
64
65    /// Try to get this value as an octet string.
66    pub fn as_octet_string(&self) -> Option<&[u8]> {
67        match self {
68            BerValue::OctetString(v) => Some(v),
69            _ => None,
70        }
71    }
72
73    /// Try to get this value as a sequence.
74    pub fn as_sequence(&self) -> Option<&[BerValue]> {
75        match self {
76            BerValue::Sequence(v) => Some(v),
77            _ => None,
78        }
79    }
80
81    /// Check if this value is null.
82    pub fn is_null(&self) -> bool {
83        matches!(self, BerValue::Null)
84    }
85
86    /// Decode a BER value from bytes.
87    pub fn decode(data: &[u8]) -> Result<Self> {
88        let mut reader = BerReader::new(data);
89        Self::decode_from_reader(&mut reader)
90    }
91
92    /// Decode a BER value from a reader.
93    pub fn decode_from_reader(reader: &mut BerReader) -> Result<Self> {
94        let (tag, value_bytes) = reader.read_tlv()?;
95        
96        if tag.is_universal() {
97            match tag.number {
98                1 => {
99                    // BOOLEAN
100                    Ok(BerValue::Boolean(value_bytes.first().map(|&b| b != 0).unwrap_or(false)))
101                }
102                2 => {
103                    // INTEGER
104                    let mut inner = BerReader::new(value_bytes);
105                    // For raw value bytes, decode directly
106                    let value = decode_integer_bytes(value_bytes)?;
107                    Ok(BerValue::Integer(value))
108                }
109                5 => {
110                    // NULL
111                    Ok(BerValue::Null)
112                }
113                9 => {
114                    // REAL
115                    let value = decode_real_bytes(value_bytes)?;
116                    Ok(BerValue::Real(value))
117                }
118                12 => {
119                    // UTF8String
120                    Ok(BerValue::String(String::from_utf8(value_bytes.to_vec())?))
121                }
122                4 => {
123                    // OCTET STRING
124                    Ok(BerValue::OctetString(value_bytes.to_vec()))
125                }
126                16 => {
127                    // SEQUENCE
128                    let mut items = Vec::new();
129                    let mut inner = BerReader::new(value_bytes);
130                    while inner.has_more() {
131                        items.push(Self::decode_from_reader(&mut inner)?);
132                    }
133                    Ok(BerValue::Sequence(items))
134                }
135                _ => {
136                    // Unknown universal tag
137                    Ok(BerValue::Raw { tag, data: value_bytes.to_vec() })
138                }
139            }
140        } else if tag.is_context() {
141            let inner_value = if tag.is_constructed() && !value_bytes.is_empty() {
142                Self::decode(value_bytes)?
143            } else {
144                BerValue::OctetString(value_bytes.to_vec())
145            };
146            Ok(BerValue::Context {
147                tag: tag.number,
148                value: Box::new(inner_value),
149            })
150        } else if tag.is_application() {
151            let inner_value = if tag.is_constructed() && !value_bytes.is_empty() {
152                Self::decode(value_bytes)?
153            } else {
154                BerValue::OctetString(value_bytes.to_vec())
155            };
156            Ok(BerValue::Application {
157                tag: tag.number,
158                value: Box::new(inner_value),
159            })
160        } else {
161            Ok(BerValue::Raw { tag, data: value_bytes.to_vec() })
162        }
163    }
164
165    /// Encode this value to bytes.
166    pub fn encode(&self) -> Result<Vec<u8>> {
167        let mut writer = BerWriter::new();
168        self.encode_to_writer(&mut writer)?;
169        Ok(writer.into_bytes())
170    }
171
172    /// Encode this value to a writer.
173    pub fn encode_to_writer(&self, writer: &mut BerWriter) -> Result<()> {
174        match self {
175            BerValue::Boolean(v) => writer.write_boolean(*v),
176            BerValue::Integer(v) => writer.write_integer(*v),
177            BerValue::Real(v) => writer.write_real(*v),
178            BerValue::String(v) => writer.write_utf8_string(v),
179            BerValue::OctetString(v) => writer.write_octet_string(v),
180            BerValue::Null => writer.write_null(),
181            BerValue::Sequence(items) => {
182                writer.write_sequence(|w| {
183                    for item in items {
184                        item.encode_to_writer(w)?;
185                    }
186                    Ok(())
187                })
188            }
189            BerValue::Context { tag, value } => {
190                writer.write_context(*tag, |w| value.encode_to_writer(w))
191            }
192            BerValue::Application { tag, value } => {
193                writer.write_application(*tag, |w| value.encode_to_writer(w))
194            }
195            BerValue::Raw { tag, data } => {
196                writer.write_tlv(tag, data);
197                Ok(())
198            }
199        }
200    }
201}
202
203/// Decode an integer from raw value bytes.
204fn decode_integer_bytes(value: &[u8]) -> Result<i64> {
205    use crate::error::BerError;
206    
207    if value.is_empty() {
208        return Err(BerError::invalid_value("INTEGER", "empty value").into());
209    }
210    
211    if value.len() > 8 {
212        return Err(BerError::invalid_value(
213            "INTEGER",
214            format!("value too large: {} bytes", value.len())
215        ).into());
216    }
217    
218    let negative = (value[0] & 0x80) != 0;
219    let mut result: i64 = if negative { -1 } else { 0 };
220    
221    for &byte in value {
222        result = (result << 8) | (byte as i64);
223    }
224    
225    Ok(result)
226}
227
228/// Decode a real from raw value bytes.
229fn decode_real_bytes(value: &[u8]) -> Result<f64> {
230    use crate::error::BerError;
231    
232    if value.is_empty() {
233        return Ok(0.0);
234    }
235    
236    let first_byte = value[0];
237    
238    // Special values
239    if first_byte == 0x40 {
240        return Ok(f64::INFINITY);
241    }
242    if first_byte == 0x41 {
243        return Ok(f64::NEG_INFINITY);
244    }
245    if first_byte == 0x42 {
246        return Ok(f64::NAN);
247    }
248    if first_byte == 0x43 {
249        return Ok(-0.0);
250    }
251    
252    // Binary encoding
253    if (first_byte & 0x80) != 0 {
254        let sign = if (first_byte & 0x40) != 0 { -1.0 } else { 1.0 };
255        let base: f64 = match (first_byte >> 4) & 0x03 {
256            0 => 2.0,
257            1 => 8.0,
258            2 => 16.0,
259            _ => return Err(BerError::invalid_value("REAL", "invalid base").into()),
260        };
261        let scale_factor = (first_byte >> 2) & 0x03;
262        let exponent_length = match first_byte & 0x03 {
263            0 => 1,
264            1 => 2,
265            2 => 3,
266            3 => value.get(1).copied().unwrap_or(0) as usize,
267            _ => unreachable!(),
268        };
269        
270        let exp_start = if (first_byte & 0x03) == 3 { 2 } else { 1 };
271        if value.len() < exp_start + exponent_length {
272            return Err(BerError::invalid_value("REAL", "truncated exponent").into());
273        }
274        
275        let exp_bytes = &value[exp_start..exp_start + exponent_length];
276        let mut exponent: i64 = if !exp_bytes.is_empty() && (exp_bytes[0] & 0x80) != 0 {
277            -1
278        } else {
279            0
280        };
281        for &b in exp_bytes {
282            exponent = (exponent << 8) | (b as i64);
283        }
284        
285        let mantissa_start = exp_start + exponent_length;
286        let mantissa_bytes = &value[mantissa_start..];
287        let mut mantissa: u64 = 0;
288        for &b in mantissa_bytes {
289            mantissa = (mantissa << 8) | (b as u64);
290        }
291        
292        let scaled_mantissa = (mantissa as f64) * (1 << scale_factor) as f64;
293        let result = sign * scaled_mantissa * base.powi(exponent as i32);
294        
295        return Ok(result);
296    }
297    
298    Err(BerError::invalid_value("REAL", "unsupported encoding").into())
299}
300
301impl From<bool> for BerValue {
302    fn from(v: bool) -> Self {
303        BerValue::Boolean(v)
304    }
305}
306
307impl From<i64> for BerValue {
308    fn from(v: i64) -> Self {
309        BerValue::Integer(v)
310    }
311}
312
313impl From<i32> for BerValue {
314    fn from(v: i32) -> Self {
315        BerValue::Integer(v as i64)
316    }
317}
318
319impl From<f64> for BerValue {
320    fn from(v: f64) -> Self {
321        BerValue::Real(v)
322    }
323}
324
325impl From<String> for BerValue {
326    fn from(v: String) -> Self {
327        BerValue::String(v)
328    }
329}
330
331impl From<&str> for BerValue {
332    fn from(v: &str) -> Self {
333        BerValue::String(v.to_string())
334    }
335}
336
337impl From<Vec<u8>> for BerValue {
338    fn from(v: Vec<u8>) -> Self {
339        BerValue::OctetString(v)
340    }
341}
342
343#[cfg(test)]
344mod tests {
345    use super::*;
346
347    #[test]
348    fn test_value_roundtrip() {
349        let values = vec![
350            BerValue::Boolean(true),
351            BerValue::Boolean(false),
352            BerValue::Integer(0),
353            BerValue::Integer(42),
354            BerValue::Integer(-1),
355            BerValue::String("Hello".to_string()),
356            BerValue::OctetString(vec![1, 2, 3]),
357            BerValue::Null,
358            BerValue::Sequence(vec![
359                BerValue::Integer(1),
360                BerValue::String("test".to_string()),
361            ]),
362        ];
363
364        for value in values {
365            let encoded = value.encode().unwrap();
366            let decoded = BerValue::decode(&encoded).unwrap();
367            assert_eq!(value, decoded);
368        }
369    }
370}