@@ -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