asn1_rs/
length.rs

1use crate::{DynTagged, Error, Result, Tag};
2#[cfg(feature = "std")]
3use crate::{SerializeResult, ToDer};
4use core::ops;
5
6/// BER Object Length
7#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8pub enum Length {
9    /// Definite form (X.690 8.1.3.3)
10    Definite(usize),
11    /// Indefinite form (X.690 8.1.3.6)
12    Indefinite,
13}
14
15impl Length {
16    /// Return true if length is definite and equal to 0
17    #[inline]
18    pub fn is_null(&self) -> bool {
19        *self == Length::Definite(0)
20    }
21
22    /// Get length of primitive object
23    #[inline]
24    pub fn definite(&self) -> Result<usize> {
25        match self {
26            Length::Definite(sz) => Ok(*sz),
27            Length::Indefinite => Err(Error::IndefiniteLengthUnexpected),
28        }
29    }
30
31    /// Return true if length is definite
32    #[inline]
33    pub const fn is_definite(&self) -> bool {
34        matches!(self, Length::Definite(_))
35    }
36
37    /// Return error if length is not definite
38    #[inline]
39    pub const fn assert_definite(&self) -> Result<()> {
40        match self {
41            Length::Definite(_) => Ok(()),
42            Length::Indefinite => Err(Error::IndefiniteLengthUnexpected),
43        }
44    }
45}
46
47impl From<usize> for Length {
48    fn from(l: usize) -> Self {
49        Length::Definite(l)
50    }
51}
52
53impl ops::Add<Length> for Length {
54    type Output = Self;
55
56    fn add(self, rhs: Length) -> Self::Output {
57        match self {
58            Length::Indefinite => self,
59            Length::Definite(lhs) => match rhs {
60                Length::Indefinite => rhs,
61                Length::Definite(rhs) => Length::Definite(lhs + rhs),
62            },
63        }
64    }
65}
66
67impl ops::Add<usize> for Length {
68    type Output = Self;
69
70    fn add(self, rhs: usize) -> Self::Output {
71        match self {
72            Length::Definite(lhs) => Length::Definite(lhs + rhs),
73            Length::Indefinite => self,
74        }
75    }
76}
77
78impl ops::AddAssign<usize> for Length {
79    fn add_assign(&mut self, rhs: usize) {
80        match self {
81            Length::Definite(ref mut lhs) => *lhs += rhs,
82            Length::Indefinite => (),
83        }
84    }
85}
86
87impl DynTagged for Length {
88    fn tag(&self) -> Tag {
89        Tag(0)
90    }
91}
92
93#[cfg(feature = "std")]
94impl ToDer for Length {
95    fn to_der_len(&self) -> Result<usize> {
96        match self {
97            Length::Indefinite => Ok(1),
98            Length::Definite(l) => match l {
99                0..=0x7f => Ok(1),
100                0x80..=0xff => Ok(2),
101                0x100..=0xffff => Ok(3),
102                0x1_0000..=0xffff_ffff => Ok(4),
103                _ => Err(Error::InvalidLength),
104            },
105        }
106    }
107
108    fn write_der_header(&self, writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
109        match *self {
110            Length::Indefinite => {
111                let sz = writer.write(&[0b1000_0000])?;
112                Ok(sz)
113            }
114            Length::Definite(l) => {
115                if l <= 127 {
116                    // Short form
117                    let sz = writer.write(&[l as u8])?;
118                    Ok(sz)
119                } else {
120                    // Long form
121                    let b = l.to_be_bytes();
122                    // skip leading zeroes
123                    // we do not have to test for length, l cannot be 0
124                    let mut idx = 0;
125                    while b[idx] == 0 {
126                        idx += 1;
127                    }
128                    let b = &b[idx..];
129                    // first byte: 0x80 + length of length
130                    let b0 = 0x80 | (b.len() as u8);
131                    let sz = writer.write(&[b0])?;
132                    let sz = sz + writer.write(b)?;
133                    Ok(sz)
134                }
135            }
136        }
137    }
138
139    fn write_der_content(&self, _writer: &mut dyn std::io::Write) -> SerializeResult<usize> {
140        Ok(0)
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use crate::*;
147
148    /// Generic and coverage tests
149    #[test]
150    fn methods_length() {
151        let l = Length::from(2);
152        assert_eq!(l.definite(), Ok(2));
153        assert!(l.assert_definite().is_ok());
154
155        let l = Length::Indefinite;
156        assert!(l.definite().is_err());
157        assert!(l.assert_definite().is_err());
158
159        let l = Length::from(2);
160        assert_eq!(l + 2, Length::from(4));
161        assert_eq!(l + Length::Indefinite, Length::Indefinite);
162
163        let l = Length::Indefinite;
164        assert_eq!(l + 2, Length::Indefinite);
165
166        let l = Length::from(2);
167        assert_eq!(l + Length::from(2), Length::from(4));
168
169        let l = Length::Indefinite;
170        assert_eq!(l + Length::from(2), Length::Indefinite);
171
172        let mut l = Length::from(2);
173        l += 2;
174        assert_eq!(l.definite(), Ok(4));
175
176        let mut l = Length::Indefinite;
177        l += 2;
178        assert_eq!(l, Length::Indefinite);
179    }
180}