Skip to main content

ember_plus/ber/
length.rs

1//! BER length encoding and decoding.
2
3use crate::error::{BerError, Result};
4
5/// BER length encoding.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Length {
8    /// Definite length
9    Definite(usize),
10    /// Indefinite length (terminated by end-of-contents)
11    Indefinite,
12}
13
14impl Length {
15    /// Create a definite length.
16    pub const fn definite(len: usize) -> Self {
17        Length::Definite(len)
18    }
19
20    /// Create an indefinite length.
21    pub const fn indefinite() -> Self {
22        Length::Indefinite
23    }
24
25    /// Check if this is a definite length.
26    pub fn is_definite(&self) -> bool {
27        matches!(self, Length::Definite(_))
28    }
29
30    /// Check if this is an indefinite length.
31    pub fn is_indefinite(&self) -> bool {
32        matches!(self, Length::Indefinite)
33    }
34
35    /// Get the definite length value, if any.
36    pub fn value(&self) -> Option<usize> {
37        match self {
38            Length::Definite(len) => Some(*len),
39            Length::Indefinite => None,
40        }
41    }
42
43    /// Encode this length to bytes.
44    pub fn encode(&self) -> Vec<u8> {
45        match self {
46            Length::Indefinite => vec![0x80],
47            Length::Definite(len) => {
48                if *len < 128 {
49                    // Short form
50                    vec![*len as u8]
51                } else {
52                    // Long form
53                    let mut bytes = Vec::new();
54                    let mut remaining = *len;
55                    
56                    while remaining > 0 {
57                        bytes.push((remaining & 0xFF) as u8);
58                        remaining >>= 8;
59                    }
60                    
61                    bytes.reverse();
62                    
63                    let mut result = vec![0x80 | (bytes.len() as u8)];
64                    result.extend(bytes);
65                    result
66                }
67            }
68        }
69    }
70
71    /// Decode a length from bytes.
72    pub fn decode(data: &[u8]) -> Result<(Self, usize)> {
73        if data.is_empty() {
74            return Err(BerError::UnexpectedEof.into());
75        }
76
77        let first_byte = data[0];
78
79        if first_byte == 0x80 {
80            // Indefinite form
81            Ok((Length::Indefinite, 1))
82        } else if (first_byte & 0x80) == 0 {
83            // Short form
84            Ok((Length::Definite(first_byte as usize), 1))
85        } else {
86            // Long form
87            let num_bytes = (first_byte & 0x7F) as usize;
88            
89            if num_bytes == 0 {
90                return Err(BerError::InvalidLength.into());
91            }
92            
93            if num_bytes > 8 {
94                return Err(BerError::LengthOverflow.into());
95            }
96            
97            if data.len() < 1 + num_bytes {
98                return Err(BerError::UnexpectedEof.into());
99            }
100
101            let mut length: usize = 0;
102            for i in 0..num_bytes {
103                length = length
104                    .checked_shl(8)
105                    .ok_or(BerError::LengthOverflow)?
106                    .checked_add(data[1 + i] as usize)
107                    .ok_or(BerError::LengthOverflow)?;
108            }
109
110            Ok((Length::Definite(length), 1 + num_bytes))
111        }
112    }
113
114    /// Calculate the encoded size of a length value.
115    pub fn encoded_size(len: usize) -> usize {
116        if len < 128 {
117            1
118        } else {
119            let mut size = 1; // Initial byte
120            let mut remaining = len;
121            while remaining > 0 {
122                size += 1;
123                remaining >>= 8;
124            }
125            size
126        }
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
135    fn test_short_length_roundtrip() {
136        for len in 0..128usize {
137            let length = Length::Definite(len);
138            let encoded = length.encode();
139            assert_eq!(encoded.len(), 1);
140            let (decoded, size) = Length::decode(&encoded).unwrap();
141            assert_eq!(size, 1);
142            assert_eq!(length, decoded);
143        }
144    }
145
146    #[test]
147    fn test_long_length_roundtrip() {
148        for len in [128usize, 255, 256, 65535, 65536, 0xFFFFFF, 0x1000000] {
149            let length = Length::Definite(len);
150            let encoded = length.encode();
151            let (decoded, size) = Length::decode(&encoded).unwrap();
152            assert_eq!(size, encoded.len());
153            assert_eq!(length, decoded);
154        }
155    }
156
157    #[test]
158    fn test_indefinite_length() {
159        let length = Length::Indefinite;
160        let encoded = length.encode();
161        assert_eq!(encoded, vec![0x80]);
162        let (decoded, size) = Length::decode(&encoded).unwrap();
163        assert_eq!(size, 1);
164        assert_eq!(length, decoded);
165    }
166}