|
| 1 | +use super::*; |
| 2 | + |
| 3 | +pub(crate) struct Decoder { |
| 4 | + buffer: Vec<u8>, |
| 5 | + i: usize, |
| 6 | +} |
| 7 | + |
| 8 | +impl Decoder { |
| 9 | + fn array<const N: usize>(&mut self) -> Result<[u8; N], DecodeError> { |
| 10 | + Ok(self.slice(N)?.try_into().unwrap()) |
| 11 | + } |
| 12 | + |
| 13 | + pub(crate) fn bytes(&mut self) -> Result<&[u8], DecodeError> { |
| 14 | + let len = self |
| 15 | + .expect(MajorType::Bytes)? |
| 16 | + .try_into() |
| 17 | + .context(decode_error::SizeRange)?; |
| 18 | + |
| 19 | + self.slice(len) |
| 20 | + } |
| 21 | + |
| 22 | + fn expect(&mut self, expected: MajorType) -> Result<u64, DecodeError> { |
| 23 | + let Head { major_type, value } = self.head()?; |
| 24 | + |
| 25 | + ensure!( |
| 26 | + major_type == expected, |
| 27 | + decode_error::UnexpectedType { |
| 28 | + actual: major_type, |
| 29 | + expected, |
| 30 | + } |
| 31 | + ); |
| 32 | + |
| 33 | + Ok(value) |
| 34 | + } |
| 35 | + |
| 36 | + pub(crate) fn finish(self) -> Result<(), DecodeError> { |
| 37 | + ensure!(self.i == self.buffer.len(), decode_error::TrailingBytes); |
| 38 | + Ok(()) |
| 39 | + } |
| 40 | + |
| 41 | + pub(crate) fn head(&mut self) -> Result<Head, DecodeError> { |
| 42 | + let initial_byte = self.array::<1>()?[0]; |
| 43 | + |
| 44 | + let major_type = MajorType::from_initial_byte(initial_byte); |
| 45 | + |
| 46 | + let additional_information = initial_byte & 0b11111; |
| 47 | + |
| 48 | + let value = match additional_information { |
| 49 | + 0..24 => additional_information.into(), |
| 50 | + 24 => u8::from_be_bytes(self.array()?).into(), |
| 51 | + 25 => u16::from_be_bytes(self.array()?).into(), |
| 52 | + 26 => u32::from_be_bytes(self.array()?).into(), |
| 53 | + 27 => u64::from_be_bytes(self.array()?), |
| 54 | + value @ 28..31 => { |
| 55 | + return Err(decode_error::ReservedAdditionalInformation { value }.build()); |
| 56 | + } |
| 57 | + value @ 31 => { |
| 58 | + return Err(decode_error::UnsupportedAdditionalInformation { value }.build()); |
| 59 | + } |
| 60 | + 32..=u8::MAX => unreachable!(), |
| 61 | + }; |
| 62 | + |
| 63 | + let min = match additional_information { |
| 64 | + 0..24 => 0, |
| 65 | + 24 => 24, |
| 66 | + 25 => 0x100, |
| 67 | + 26 => 0x1_0000, |
| 68 | + 27 => 0x1_0000_0000, |
| 69 | + _ => unreachable!(), |
| 70 | + }; |
| 71 | + |
| 72 | + ensure!(value >= min, decode_error::OverlongInteger); |
| 73 | + |
| 74 | + Ok(Head { major_type, value }) |
| 75 | + } |
| 76 | + |
| 77 | + pub(crate) fn integer(&mut self) -> Result<u64, DecodeError> { |
| 78 | + self.expect(MajorType::Integer) |
| 79 | + } |
| 80 | + |
| 81 | + pub(crate) fn map<K>(&mut self) -> Result<MapDecoder<K>, DecodeError> { |
| 82 | + let len = self.expect(MajorType::Map)?; |
| 83 | + Ok(MapDecoder::new(self, len)) |
| 84 | + } |
| 85 | + |
| 86 | + pub(crate) fn new(buffer: Vec<u8>) -> Self { |
| 87 | + Self { buffer, i: 0 } |
| 88 | + } |
| 89 | + |
| 90 | + fn slice(&mut self, n: usize) -> Result<&[u8], DecodeError> { |
| 91 | + let start = self.i; |
| 92 | + let end = start + n; |
| 93 | + |
| 94 | + ensure! { |
| 95 | + end <= self.buffer.len(), |
| 96 | + decode_error::Truncated, |
| 97 | + } |
| 98 | + |
| 99 | + self.i = end; |
| 100 | + |
| 101 | + Ok(&self.buffer[start..end]) |
| 102 | + } |
| 103 | + |
| 104 | + pub(crate) fn text(&mut self) -> Result<&str, DecodeError> { |
| 105 | + let len = self |
| 106 | + .expect(MajorType::Text)? |
| 107 | + .try_into() |
| 108 | + .context(decode_error::SizeRange)?; |
| 109 | + |
| 110 | + str::from_utf8(self.slice(len)?).context(decode_error::Unicode) |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | +#[cfg(test)] |
| 115 | +mod tests { |
| 116 | + use super::*; |
| 117 | + |
| 118 | + #[test] |
| 119 | + fn integer_range() { |
| 120 | + assert!(matches!( |
| 121 | + u8::decode(&mut Decoder::new(256u64.encode_to_vec())), |
| 122 | + Err(DecodeError::IntegerRange { .. }), |
| 123 | + )); |
| 124 | + } |
| 125 | + |
| 126 | + #[test] |
| 127 | + fn overlong_integer() { |
| 128 | + #[track_caller] |
| 129 | + fn case(bytes: &[u8]) { |
| 130 | + assert_eq!( |
| 131 | + Decoder::new(bytes.to_vec()).head(), |
| 132 | + Err(DecodeError::OverlongInteger), |
| 133 | + ); |
| 134 | + } |
| 135 | + |
| 136 | + case(&[0x18, 0x17]); |
| 137 | + case(&[0x19, 0x00, 0xFF]); |
| 138 | + case(&[0x1A, 0x00, 0x00, 0xFF, 0xFF]); |
| 139 | + case(&[0x1B, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]); |
| 140 | + } |
| 141 | + |
| 142 | + #[test] |
| 143 | + fn reserved_additional_information() { |
| 144 | + assert_eq!( |
| 145 | + Decoder::new(vec![0x1C]).head(), |
| 146 | + Err(DecodeError::ReservedAdditionalInformation { value: 28 }), |
| 147 | + ); |
| 148 | + } |
| 149 | + |
| 150 | + #[test] |
| 151 | + fn trailing_bytes() { |
| 152 | + assert_eq!( |
| 153 | + Decoder::new(vec![0x00]).finish(), |
| 154 | + Err(DecodeError::TrailingBytes) |
| 155 | + ); |
| 156 | + } |
| 157 | + |
| 158 | + #[test] |
| 159 | + fn truncated() { |
| 160 | + assert_eq!(Decoder::new(vec![]).head(), Err(DecodeError::Truncated),); |
| 161 | + } |
| 162 | + |
| 163 | + #[test] |
| 164 | + fn type_mismatch() { |
| 165 | + assert_eq!( |
| 166 | + Decoder::new(vec![0x60]).integer(), |
| 167 | + Err(DecodeError::UnexpectedType { |
| 168 | + expected: MajorType::Integer, |
| 169 | + actual: MajorType::Text, |
| 170 | + }), |
| 171 | + ); |
| 172 | + } |
| 173 | + |
| 174 | + #[test] |
| 175 | + #[expect(invalid_from_utf8)] |
| 176 | + fn unicode() { |
| 177 | + assert_eq!( |
| 178 | + Decoder::new(vec![0x62, 0xFF, 0xFE]).text().map(drop), |
| 179 | + Err(DecodeError::Unicode { |
| 180 | + source: str::from_utf8(&[0xFF, 0xFE]).unwrap_err() |
| 181 | + }), |
| 182 | + ); |
| 183 | + } |
| 184 | + |
| 185 | + #[test] |
| 186 | + fn unsupported_additional_information() { |
| 187 | + assert_eq!( |
| 188 | + Decoder::new(vec![0x1F]).head(), |
| 189 | + Err(DecodeError::UnsupportedAdditionalInformation { value: 31 }), |
| 190 | + ); |
| 191 | + } |
| 192 | +} |
0 commit comments