Skip to main content

ember_plus/ber/
reader.rs

1//! BER reader for decoding BER-encoded data.
2
3use super::{Tag, Length};
4use crate::error::{BerError, Result};
5
6/// A reader for BER-encoded data.
7#[derive(Debug)]
8pub struct BerReader<'a> {
9    data: &'a [u8],
10    pos: usize,
11}
12
13impl<'a> BerReader<'a> {
14    /// Create a new BER reader.
15    pub fn new(data: &'a [u8]) -> Self {
16        BerReader { data, pos: 0 }
17    }
18
19    /// Get the current position.
20    pub fn position(&self) -> usize {
21        self.pos
22    }
23
24    /// Get the remaining bytes.
25    pub fn remaining(&self) -> &[u8] {
26        &self.data[self.pos..]
27    }
28
29    /// Check if there is more data to read.
30    pub fn has_more(&self) -> bool {
31        self.pos < self.data.len()
32    }
33
34    /// Peek at the next tag without advancing.
35    pub fn peek_tag(&self) -> Result<Tag> {
36        let (tag, _) = Tag::decode(self.remaining())?;
37        Ok(tag)
38    }
39
40    /// Read a tag.
41    pub fn read_tag(&mut self) -> Result<Tag> {
42        let (tag, len) = Tag::decode(self.remaining())?;
43        self.pos += len;
44        Ok(tag)
45    }
46
47    /// Read a length.
48    pub fn read_length(&mut self) -> Result<Length> {
49        let (length, len) = Length::decode(self.remaining())?;
50        self.pos += len;
51        Ok(length)
52    }
53
54    /// Read raw bytes.
55    pub fn read_bytes(&mut self, count: usize) -> Result<&'a [u8]> {
56        if self.pos + count > self.data.len() {
57            return Err(BerError::UnexpectedEof.into());
58        }
59        let bytes = &self.data[self.pos..self.pos + count];
60        self.pos += count;
61        Ok(bytes)
62    }
63
64    /// Read a TLV (Tag-Length-Value) and return the value bytes.
65    pub fn read_tlv(&mut self) -> Result<(Tag, &'a [u8])> {
66        let tag = self.read_tag()?;
67        let length = self.read_length()?;
68        
69        let value = match length {
70            Length::Definite(len) => self.read_bytes(len)?,
71            Length::Indefinite => {
72                // Find end-of-contents marker (00 00)
73                let start = self.pos;
74                loop {
75                    if self.pos + 1 >= self.data.len() {
76                        return Err(BerError::UnexpectedEof.into());
77                    }
78                    if self.data[self.pos] == 0x00 && self.data[self.pos + 1] == 0x00 {
79                        let value = &self.data[start..self.pos];
80                        self.pos += 2; // Skip end-of-contents
81                        break value;
82                    }
83                    self.pos += 1;
84                }
85            }
86        };
87        
88        Ok((tag, value))
89    }
90
91    /// Read a boolean value.
92    pub fn read_boolean(&mut self) -> Result<bool> {
93        let (tag, value) = self.read_tlv()?;
94        
95        if tag != Tag::BOOLEAN {
96            return Err(BerError::InvalidTag(format!(
97                "expected BOOLEAN tag, got {:?}", tag
98            )).into());
99        }
100        
101        if value.len() != 1 {
102            return Err(BerError::invalid_value(
103                "BOOLEAN",
104                format!("expected 1 byte, got {}", value.len())
105            ).into());
106        }
107        
108        Ok(value[0] != 0)
109    }
110
111    /// Read an integer value.
112    pub fn read_integer(&mut self) -> Result<i64> {
113        let (tag, value) = self.read_tlv()?;
114        
115        if tag != Tag::INTEGER {
116            return Err(BerError::InvalidTag(format!(
117                "expected INTEGER tag, got {:?}", tag
118            )).into());
119        }
120        
121        Self::decode_integer(value)
122    }
123
124    /// Read an integer with a context tag.
125    pub fn read_context_integer(&mut self, expected_tag: u32) -> Result<i64> {
126        let (tag, value) = self.read_tlv()?;
127        
128        if !tag.is_context() || tag.number != expected_tag {
129            return Err(BerError::InvalidTag(format!(
130                "expected context tag [{}], got {:?}", expected_tag, tag
131            )).into());
132        }
133        
134        // The value might be a nested INTEGER TLV or raw bytes
135        if !value.is_empty() && value[0] == Tag::INTEGER.encode()[0] {
136            let mut inner = BerReader::new(value);
137            inner.read_integer()
138        } else {
139            Self::decode_integer(value)
140        }
141    }
142
143    /// Decode an integer from raw bytes.
144    fn decode_integer(value: &[u8]) -> Result<i64> {
145        if value.is_empty() {
146            return Err(BerError::invalid_value(
147                "INTEGER",
148                "empty value"
149            ).into());
150        }
151        
152        if value.len() > 8 {
153            return Err(BerError::invalid_value(
154                "INTEGER",
155                format!("value too large: {} bytes", value.len())
156            ).into());
157        }
158        
159        // Sign-extend if negative
160        let negative = (value[0] & 0x80) != 0;
161        let mut result: i64 = if negative { -1 } else { 0 };
162        
163        for &byte in value {
164            result = (result << 8) | (byte as i64);
165        }
166        
167        Ok(result)
168    }
169
170    /// Read a real (floating point) value.
171    pub fn read_real(&mut self) -> Result<f64> {
172        let (tag, value) = self.read_tlv()?;
173        
174        if tag != Tag::REAL {
175            return Err(BerError::InvalidTag(format!(
176                "expected REAL tag, got {:?}", tag
177            )).into());
178        }
179        
180        Self::decode_real(value)
181    }
182
183    /// Decode a real from raw bytes.
184    fn decode_real(value: &[u8]) -> Result<f64> {
185        if value.is_empty() {
186            return Ok(0.0);
187        }
188        
189        let first_byte = value[0];
190        
191        // Special values
192        if first_byte == 0x40 {
193            return Ok(f64::INFINITY);
194        }
195        if first_byte == 0x41 {
196            return Ok(f64::NEG_INFINITY);
197        }
198        if first_byte == 0x42 {
199            return Ok(f64::NAN);
200        }
201        if first_byte == 0x43 {
202            return Ok(-0.0);
203        }
204        
205        // Binary encoding
206        if (first_byte & 0x80) != 0 {
207            let sign: f64 = if (first_byte & 0x40) != 0 { -1.0 } else { 1.0 };
208            let base: f64 = match (first_byte >> 4) & 0x03 {
209                0 => 2.0,
210                1 => 8.0,
211                2 => 16.0,
212                _ => return Err(BerError::invalid_value("REAL", "invalid base").into()),
213            };
214            let scale_factor = (first_byte >> 2) & 0x03;
215            let exponent_length = match first_byte & 0x03 {
216                0 => 1,
217                1 => 2,
218                2 => 3,
219                3 => value.get(1).copied().unwrap_or(0) as usize,
220                _ => unreachable!(),
221            };
222            
223            let exp_start = if (first_byte & 0x03) == 3 { 2 } else { 1 };
224            if value.len() < exp_start + exponent_length {
225                return Err(BerError::invalid_value("REAL", "truncated exponent").into());
226            }
227            
228            let exp_bytes = &value[exp_start..exp_start + exponent_length];
229            let mut exponent: i64 = if !exp_bytes.is_empty() && (exp_bytes[0] & 0x80) != 0 {
230                -1
231            } else {
232                0
233            };
234            for &b in exp_bytes {
235                exponent = (exponent << 8) | (b as i64);
236            }
237            
238            let mantissa_start = exp_start + exponent_length;
239            let mantissa_bytes = &value[mantissa_start..];
240            let mut mantissa: u64 = 0;
241            for &b in mantissa_bytes {
242                mantissa = (mantissa << 8) | (b as u64);
243            }
244            
245            let scaled_mantissa = (mantissa as f64) * (1 << scale_factor) as f64;
246            let result = sign * scaled_mantissa * base.powi(exponent as i32);
247            
248            return Ok(result);
249        }
250        
251        // Decimal encoding (ISO 6093)
252        if (first_byte & 0xC0) == 0 {
253            let s = std::str::from_utf8(&value[1..])
254                .map_err(|_| BerError::invalid_value("REAL", "invalid decimal string"))?;
255            return s.trim().parse::<f64>()
256                .map_err(|_| BerError::invalid_value("REAL", "invalid decimal value").into());
257        }
258        
259        Err(BerError::invalid_value("REAL", "unsupported encoding").into())
260    }
261
262    /// Read a UTF-8 string.
263    pub fn read_utf8_string(&mut self) -> Result<String> {
264        let (tag, value) = self.read_tlv()?;
265        
266        if tag != Tag::UTF8_STRING {
267            return Err(BerError::InvalidTag(format!(
268                "expected UTF8String tag, got {:?}", tag
269            )).into());
270        }
271        
272        Ok(String::from_utf8(value.to_vec())?)
273    }
274
275    /// Read an octet string.
276    pub fn read_octet_string(&mut self) -> Result<Vec<u8>> {
277        let (tag, value) = self.read_tlv()?;
278        
279        if tag != Tag::OCTET_STRING {
280            return Err(BerError::InvalidTag(format!(
281                "expected OCTET STRING tag, got {:?}", tag
282            )).into());
283        }
284        
285        Ok(value.to_vec())
286    }
287
288    /// Read a sequence and return a reader for its contents.
289    pub fn read_sequence(&mut self) -> Result<BerReader<'a>> {
290        let (tag, value) = self.read_tlv()?;
291        
292        if tag != Tag::SEQUENCE {
293            return Err(BerError::InvalidTag(format!(
294                "expected SEQUENCE tag, got {:?}", tag
295            )).into());
296        }
297        
298        Ok(BerReader::new(value))
299    }
300
301    /// Read a context-tagged value and return a reader for its contents.
302    pub fn read_context(&mut self, expected_tag: u32) -> Result<BerReader<'a>> {
303        let (tag, value) = self.read_tlv()?;
304        
305        if !tag.is_context() || tag.number != expected_tag {
306            return Err(BerError::InvalidTag(format!(
307                "expected context tag [{}], got {:?}", expected_tag, tag
308            )).into());
309        }
310        
311        Ok(BerReader::new(value))
312    }
313
314    /// Read an application-tagged value and return a reader for its contents.
315    pub fn read_application(&mut self, expected_tag: u32) -> Result<BerReader<'a>> {
316        let (tag, value) = self.read_tlv()?;
317        
318        if !tag.is_application() || tag.number != expected_tag {
319            return Err(BerError::InvalidTag(format!(
320                "expected application tag [{}], got {:?}", expected_tag, tag
321            )).into());
322        }
323        
324        Ok(BerReader::new(value))
325    }
326
327    /// Skip the current TLV.
328    pub fn skip(&mut self) -> Result<()> {
329        let _ = self.read_tlv()?;
330        Ok(())
331    }
332
333    /// Read a relative OID.
334    pub fn read_relative_oid(&mut self) -> Result<Vec<u32>> {
335        let (tag, value) = self.read_tlv()?;
336        
337        if tag != Tag::RELATIVE_OID {
338            return Err(BerError::InvalidTag(format!(
339                "expected RELATIVE-OID tag, got {:?}", tag
340            )).into());
341        }
342        
343        let mut components = Vec::new();
344        let mut current: u32 = 0;
345        
346        for &byte in value {
347            current = current
348                .checked_shl(7)
349                .ok_or(BerError::LengthOverflow)?
350                .checked_add((byte & 0x7F) as u32)
351                .ok_or(BerError::LengthOverflow)?;
352            
353            if (byte & 0x80) == 0 {
354                components.push(current);
355                current = 0;
356            }
357        }
358        
359        Ok(components)
360    }
361}