use crate::{Decode, ErrorKind, Header, Length, Reader};
#[cfg(feature = "alloc")]
use crate::Tag;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
const EOC_TAG: u8 = 0x00;
pub(super) fn decode_indefinite_length<'a>(reader: &mut impl Reader<'a>) -> crate::Result<Length> {
let start_pos = reader.position();
loop {
if reader.peek_byte() == Some(EOC_TAG) {
read_eoc(reader)?;
let mut ret = (reader.position() - start_pos)?;
ret.indefinite = true;
return Ok(ret);
}
let header = Header::decode(reader)?;
reader.drain(header.length())?;
}
}
pub(crate) fn read_eoc<'a>(reader: &mut impl Reader<'a>) -> crate::Result<()> {
for _ in 0..Length::EOC_LEN.inner as usize {
if reader.read_byte()? != 0 {
return Err(reader.error(ErrorKind::IndefiniteLength));
}
}
Ok(())
}
#[cfg(feature = "alloc")]
pub(crate) fn read_constructed_vec<'r, R: Reader<'r>>(
reader: &mut R,
length: Length,
inner_tag: Tag,
) -> crate::Result<Vec<u8>> {
if !length.is_indefinite() {
return Err(reader.error(ErrorKind::IndefiniteLength));
}
let mut bytes = Vec::with_capacity(length.try_into()?);
let mut offset = 0;
while !reader.is_finished() {
let h = Header::decode(reader)?;
h.tag().assert_eq(inner_tag)?;
if h.length().is_indefinite() {
return Err(reader.error(ErrorKind::IndefiniteLength));
}
let l = usize::try_from(h.length())?;
bytes.extend(core::iter::repeat_n(0, l));
reader.read_into(&mut bytes[offset..(offset + l)])?;
offset += l;
}
Ok(bytes)
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use crate::{Decode, EncodingRules, Length, Reader, SliceReader, Tag};
use hex_literal::hex;
#[test]
fn decode() {
const EXAMPLE_LEN: usize = 68;
const EXAMPLE_BER: [u8; EXAMPLE_LEN] = hex!(
"30 80 06 09 2A 86 48 86 F7 0D 01 07 01
30 1D 06 09 60 86 48 01 65 03 04 01 2A 04 10 37
34 3D F1 47 0D F6 25 EE B6 F4 BF D2 F1 AC C3 A0
80 04 10 CC 74 AD F6 5D 97 3C 8B 72 CD 51 E1 B9
27 F0 F0 00 00 00 00"
);
assert!(!Length::from_der(&[0x00]).unwrap().indefinite);
let mut reader =
SliceReader::new_with_encoding_rules(&EXAMPLE_BER, EncodingRules::Ber).unwrap();
let tag = Tag::decode(&mut reader).unwrap();
assert_eq!(tag, Tag::Sequence);
let length = Length::decode(&mut reader).unwrap();
assert!(length.is_indefinite());
let pos = usize::try_from(reader.position()).unwrap();
assert_eq!(pos, 2);
assert_eq!(usize::try_from(length).unwrap(), EXAMPLE_LEN - pos);
reader.tlv_bytes().unwrap();
reader.tlv_bytes().unwrap();
let tag = Tag::decode(&mut reader).unwrap();
assert_eq!(
tag,
Tag::ContextSpecific {
constructed: true,
number: 0u32.into()
}
);
let length = Length::decode(&mut reader).unwrap();
assert!(length.is_indefinite());
assert_eq!(usize::try_from(length).unwrap(), 20);
}
}