Skip to main content

ldap_client_ber/
tag.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3/// BER tag class (top 2 bits of the identifier byte).
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5#[repr(u8)]
6pub enum Class {
7    Universal = 0,
8    Application = 1,
9    Context = 2,
10    Private = 3,
11}
12
13impl Class {
14    pub fn from_byte(b: u8) -> Self {
15        match b >> 6 {
16            0 => Self::Universal,
17            1 => Self::Application,
18            2 => Self::Context,
19            3 => Self::Private,
20            _ => unreachable!(),
21        }
22    }
23}
24
25/// Fully decoded BER tag: class + constructed flag + tag number.
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
27pub struct Tag {
28    pub class: Class,
29    pub constructed: bool,
30    pub number: u32,
31}
32
33impl Tag {
34    pub const fn universal(number: u32) -> Self {
35        Self {
36            class: Class::Universal,
37            constructed: false,
38            number,
39        }
40    }
41
42    pub const fn sequence() -> Self {
43        Self {
44            class: Class::Universal,
45            constructed: true,
46            number: SEQUENCE,
47        }
48    }
49
50    pub const fn set() -> Self {
51        Self {
52            class: Class::Universal,
53            constructed: true,
54            number: SET,
55        }
56    }
57
58    pub const fn context(number: u32) -> Self {
59        Self {
60            class: Class::Context,
61            constructed: false,
62            number,
63        }
64    }
65
66    pub const fn context_constructed(number: u32) -> Self {
67        Self {
68            class: Class::Context,
69            constructed: true,
70            number,
71        }
72    }
73
74    pub const fn application(number: u32) -> Self {
75        Self {
76            class: Class::Application,
77            constructed: true,
78            number,
79        }
80    }
81
82    pub const fn application_primitive(number: u32) -> Self {
83        Self {
84            class: Class::Application,
85            constructed: false,
86            number,
87        }
88    }
89
90    pub fn with_constructed(self, constructed: bool) -> Self {
91        Self {
92            constructed,
93            ..self
94        }
95    }
96
97    /// Encode the identifier byte(s).
98    pub fn encode(&self) -> Vec<u8> {
99        let mut first = (self.class as u8) << 6;
100        if self.constructed {
101            first |= 0x20;
102        }
103
104        if self.number < 31 {
105            first |= self.number as u8;
106            vec![first]
107        } else {
108            first |= 0x1F;
109            // Encode tag number in base-128. A u32 needs at most 5 base-128 digits.
110            let mut buf = [0u8; 5];
111            let mut pos = buf.len();
112            let mut n = self.number;
113            loop {
114                pos -= 1;
115                buf[pos] = (n & 0x7F) as u8;
116                n >>= 7;
117                if n == 0 {
118                    break;
119                }
120            }
121            // Set continuation bits on all but the last byte.
122            let end = buf.len() - 1;
123            for b in &mut buf[pos..end] {
124                *b |= 0x80;
125            }
126            let mut result = Vec::with_capacity(1 + buf.len() - pos);
127            result.push(first);
128            result.extend_from_slice(&buf[pos..]);
129            result
130        }
131    }
132}
133
134// Well-known universal tag numbers.
135pub const BOOLEAN: u32 = 0x01;
136pub const INTEGER: u32 = 0x02;
137pub const OCTET_STRING: u32 = 0x04;
138pub const NULL: u32 = 0x05;
139pub const ENUMERATED: u32 = 0x0A;
140pub const SEQUENCE: u32 = 0x10;
141pub const SET: u32 = 0x11;