1#[cfg(feature = "ber")]
4use crate::EncodingRules;
5use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Tag, Writer};
6
7use core::cmp::Ordering;
8
9#[derive(Copy, Clone, Debug, Eq, PartialEq)]
32pub struct Header {
33 tag: Tag,
35
36 length: Length,
38
39 constructed: bool,
41}
42
43impl Header {
44 #[must_use]
46 pub fn new(tag: Tag, length: Length) -> Self {
47 #[cfg(feature = "ber")]
48 let constructed = tag.is_constructed() || length.is_indefinite();
49 #[cfg(not(feature = "ber"))]
50 let constructed = tag.is_constructed();
51 Self {
52 tag,
53 length,
54 constructed,
55 }
56 }
57
58 #[must_use]
60 pub fn tag(&self) -> Tag {
61 self.tag
62 }
63
64 #[must_use]
66 pub fn length(&self) -> Length {
67 self.length
68 }
69
70 #[must_use]
72 pub fn is_constructed(&self) -> bool {
73 self.constructed
74 }
75
76 #[must_use]
78 pub fn with_length(&self, length: Length) -> Self {
79 Self {
80 tag: self.tag,
81 length,
82 constructed: self.constructed,
83 }
84 }
85
86 pub fn peek<'a>(reader: &impl Reader<'a>) -> Result<Self> {
93 Header::decode(&mut reader.clone())
94 }
95}
96
97impl<'a> Decode<'a> for Header {
98 type Error = Error;
99
100 fn decode<R: Reader<'a>>(reader: &mut R) -> Result<Header> {
101 let (tag, is_constructed) = Tag::decode_with_constructed_bit(reader)?;
102
103 let length = Length::decode(reader).map_err(|e| {
104 if e.kind() == ErrorKind::Overlength {
105 reader.error(tag.length_error())
106 } else {
107 e
108 }
109 })?;
110
111 #[cfg(feature = "ber")]
112 if length.is_indefinite() && !is_constructed {
113 debug_assert_eq!(reader.encoding_rules(), EncodingRules::Ber);
114 return Err(reader.error(ErrorKind::IndefiniteLength));
115 }
116
117 #[cfg(not(feature = "ber"))]
118 debug_assert_eq!(is_constructed, tag.is_constructed());
119
120 Ok(Self {
121 tag,
122 length,
123 constructed: is_constructed,
124 })
125 }
126}
127
128impl Encode for Header {
129 fn encoded_len(&self) -> Result<Length> {
130 self.tag.encoded_len()? + self.length.encoded_len()?
131 }
132
133 fn encode(&self, writer: &mut impl Writer) -> Result<()> {
134 self.tag.encode(writer)?;
135 self.length.encode(writer)
136 }
137}
138
139impl DerOrd for Header {
140 fn der_cmp(&self, other: &Self) -> Result<Ordering> {
141 match self.tag.der_cmp(&other.tag)? {
142 Ordering::Equal => self.length.der_cmp(&other.length),
143 ordering => Ok(ordering),
144 }
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::Header;
151 use crate::{Encode, Length, Reader, SliceReader, Tag, TagNumber};
152 use hex_literal::hex;
153
154 #[test]
155 fn peek() {
156 const EXAMPLE_MSG: &[u8] = &hex!("02012A00");
158
159 let reader = SliceReader::new(EXAMPLE_MSG).expect("slice to be valid length");
160 assert_eq!(reader.position(), Length::ZERO);
161
162 let header = Header::peek(&reader).expect("peeked tag");
163 assert_eq!(header.tag(), Tag::Integer);
164 assert_eq!(header.length(), Length::ONE);
165 assert_eq!(reader.position(), Length::ZERO); }
167
168 #[test]
169 fn peek_max_header() {
170 const MAX_HEADER: [u8; 11] = hex!("BF8FFFFFFF7F 84FFFFFFFF");
171 let reader = SliceReader::new(&MAX_HEADER).expect("slice to be valid length");
172
173 let header = Header::peek(&reader).expect("peeked tag");
174 assert_eq!(
175 header.tag,
176 Tag::ContextSpecific {
177 constructed: true,
178 number: TagNumber(0xFFFFFFFF)
179 }
180 );
181 assert_eq!(
182 header.length(),
183 Length::new_usize(0xFFFFFFFF).expect("u32 to fit")
184 );
185 assert_eq!(header.encoded_len(), Ok(Length::new(11)));
186 assert_eq!(reader.position(), Length::ZERO); }
188 #[test]
189 fn negative_peek_overlength_header() {
190 const MAX_HEADER: [u8; 12] = hex!("BF8FFFFFFFFF7F 84FFFFFFFF");
191 let reader = SliceReader::new(&MAX_HEADER).expect("slice to be valid length");
192 Header::peek(&reader).expect_err("overlength error");
194 }
195}