Skip to content

Commit c064265

Browse files
authored
der: refactor indefinite length decoder (#1902)
Extracts it out of `BytesOwned` so it's generally useful
1 parent d937130 commit c064265

2 files changed

Lines changed: 39 additions & 24 deletions

File tree

der/src/bytes_owned.rs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
//! library-level length limitation i.e. `Length::max()`.
33
44
use crate::{
5-
BytesRef, Decode, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, Header, Length, Reader,
6-
Result, StrRef, Writer, referenced::OwnedToRef,
5+
BytesRef, DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, StrRef,
6+
Writer, reader::read_constructed_vec, referenced::OwnedToRef,
77
};
88
use alloc::{boxed::Box, vec::Vec};
99
use core::cmp::Ordering;
@@ -66,28 +66,7 @@ impl<'a> DecodeValue<'a> for BytesOwned {
6666
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
6767
// Reassemble indefinite length string types
6868
if header.length.is_indefinite() && !header.tag.is_constructed() {
69-
// Parse constructed indefinite length data
70-
// TODO(tarcieri): extract this somewhere reusable
71-
let mut bytes = Vec::with_capacity(header.length.try_into()?);
72-
let mut offset = 0;
73-
74-
while !reader.is_finished() {
75-
let h = Header::decode(reader)?;
76-
h.tag.assert_eq(header.tag)?;
77-
78-
// Indefinite length headers can't be indefinite
79-
if h.length.is_indefinite() {
80-
return Err(reader.error(ErrorKind::IndefiniteLength));
81-
}
82-
83-
// Add enough zeroes into the `Vec` to store the chunk
84-
let l = usize::try_from(h.length)?;
85-
bytes.extend(core::iter::repeat_n(0, l));
86-
reader.read_into(&mut bytes[offset..(offset + l)])?;
87-
offset += l;
88-
}
89-
90-
return Self::new(bytes);
69+
return Self::new(read_constructed_vec(reader, header)?);
9170
}
9271

9372
reader.read_vec(header.length).and_then(Self::new)

der/src/reader.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,39 @@ where
223223

224224
Ok(ret)
225225
}
226+
227+
/// Read a constructed value into a [`Vec`], removing intermediate headers and assembling the result
228+
/// into a single contiguous bytestring.
229+
///
230+
/// The end-of-content marker is not handled by this function. Instead, it's expected for this to
231+
/// be called with a nested reader which ends immediately before the EOC.
232+
#[cfg(feature = "alloc")]
233+
pub(crate) fn read_constructed_vec<'r, R: Reader<'r>>(
234+
reader: &mut R,
235+
header: Header,
236+
) -> crate::Result<Vec<u8>> {
237+
if !header.length.is_indefinite() {
238+
return Err(reader.error(ErrorKind::IndefiniteLength));
239+
}
240+
241+
let mut bytes = Vec::with_capacity(header.length.try_into()?);
242+
let mut offset = 0;
243+
244+
while !reader.is_finished() {
245+
let h = Header::decode(reader)?;
246+
h.tag.assert_eq(header.tag)?;
247+
248+
// Indefinite length headers can't be indefinite
249+
if h.length.is_indefinite() {
250+
return Err(reader.error(ErrorKind::IndefiniteLength));
251+
}
252+
253+
// Add enough zeroes into the `Vec` to store the chunk
254+
let l = usize::try_from(h.length)?;
255+
bytes.extend(core::iter::repeat_n(0, l));
256+
reader.read_into(&mut bytes[offset..(offset + l)])?;
257+
offset += l;
258+
}
259+
260+
Ok(bytes)
261+
}

0 commit comments

Comments
 (0)