Skip to content

Commit 0461b4a

Browse files
committed
EBML: Properly parse element ID VInts
Signed-off-by: Serial <69764315+Serial-ATA@users.noreply.github.com>
1 parent 5423e14 commit 0461b4a

File tree

2 files changed

+53
-9
lines changed

2 files changed

+53
-9
lines changed

src/ebml/element_reader.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl ElementHeader {
1818
R: Read,
1919
{
2020
Ok(Self {
21-
id: VInt::parse(reader, max_id_length)?,
21+
id: VInt::parse_from_element_id(reader, max_id_length)?,
2222
size: VInt::parse(reader, max_vint_length)?,
2323
})
2424
}

src/ebml/vint.rs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,48 @@ impl VInt {
101101
where
102102
R: Read,
103103
{
104-
// A value of 0b0000_0000 indicates either an invalid VInt, or one with an octet length > 8
105104
let start = reader.read_u8()?;
106-
if start == 0b0000_0000 {
107-
err!(BadVintSize);
108-
}
105+
let octet_length = Self::verify_length(start, max_length)?;
109106

110-
let octet_length = (Self::MAX_OCTET_LENGTH as u32) - start.ilog2();
111-
if octet_length > 8 || octet_length as u8 > max_length {
112-
err!(BadVintSize);
107+
let mut bytes_read = 1;
108+
let mut val = u64::from(start) ^ (1 << start.ilog2()) as u64;
109+
while bytes_read < octet_length {
110+
bytes_read += 1;
111+
val = (val << 8) | u64::from(reader.read_u8()?);
113112
}
114113

114+
Ok(Self(val))
115+
}
116+
117+
/// Parse a `VInt` from a reader, given the element ID
118+
///
119+
/// An element ID is parsed similarly to a normal `VInt`, but the `VINT_MARKER` is not
120+
/// removed.
121+
///
122+
/// # Errors
123+
///
124+
/// * `uint` cannot fit within the maximum width
125+
///
126+
/// # Examples
127+
///
128+
/// ```rust
129+
/// use lofty::ebml::VInt;
130+
///
131+
/// # fn main() -> lofty::Result<()> {
132+
/// // Parse the EBML header element ID
133+
/// let mut reader = &[0x1A, 0x45, 0xDF, 0xA3];
134+
/// let vint = VInt::parse_from_element_id(&mut reader, 8)?;
135+
/// assert_eq!(vint.value(), 0x1A45DFA3);
136+
/// # Ok(()) }
137+
pub fn parse_from_element_id<R>(reader: &mut R, max_id_length: u8) -> Result<Self>
138+
where
139+
R: Read,
140+
{
141+
let start = reader.read_u8()?;
142+
let octet_length = Self::verify_length(start, max_id_length)?;
143+
115144
let mut bytes_read = 1;
116-
let mut val = u64::from(start) ^ (1 << start.ilog2()) as u64;
145+
let mut val = u64::from(start);
117146
while bytes_read < octet_length {
118147
bytes_read += 1;
119148
val = (val << 8) | u64::from(reader.read_u8()?);
@@ -122,6 +151,21 @@ impl VInt {
122151
Ok(Self(val))
123152
}
124153

154+
// Verify that the octet length is nonzero and <= 8
155+
fn verify_length(first_byte: u8, max_length: u8) -> Result<u32> {
156+
// A value of 0b0000_0000 indicates either an invalid VInt, or one with an octet length > 8
157+
if first_byte == 0b0000_0000 {
158+
err!(BadVintSize);
159+
}
160+
161+
let octet_length = (Self::MAX_OCTET_LENGTH as u32) - first_byte.ilog2();
162+
if octet_length > 8 || octet_length as u8 > max_length {
163+
err!(BadVintSize);
164+
}
165+
166+
Ok(octet_length)
167+
}
168+
125169
/// Represents the length of the `VInt` in octets
126170
///
127171
/// NOTE: The value returned will always be <= 8

0 commit comments

Comments
 (0)