mkv_element/
base.rs

1use crate::error::Error;
2use crate::functional::*;
3use crate::io::blocking_impl::*;
4use std::fmt::Debug;
5use std::fmt::Display;
6use std::ops::Deref;
7
8/// A variable-length integer RFC 8794
9#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
10pub struct VInt64 {
11    /// The decoded integer value.
12    pub value: u64,
13    /// Whether this VInt64 represents an unknown size.
14    pub is_unknown: bool,
15}
16
17impl Display for VInt64 {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        // write!(f, "{}", self.as_encoded())
20        let encoded = self.as_encoded();
21        if encoded <= 0xFF {
22            write!(f, "0x{:02X}", encoded)
23        } else if encoded <= 0xFFFF {
24            write!(f, "0x{:04X}", encoded)
25        } else if encoded <= 0xFFFFFF {
26            write!(f, "0x{:06X}", encoded)
27        } else if encoded <= 0xFFFFFFFF {
28            write!(f, "0x{:08X}", encoded)
29        } else if encoded <= 0xFFFFFFFFFF {
30            write!(f, "0x{:010X}", encoded)
31        } else if encoded <= 0xFFFFFFFFFFFF {
32            write!(f, "0x{:012X}", encoded)
33        } else if encoded <= 0xFFFFFFFFFFFFFF {
34            write!(f, "0x{:014X}", encoded)
35        } else {
36            write!(f, "0x{:016X}", encoded)
37        }
38    }
39}
40impl Debug for VInt64 {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        let mut t = f.debug_struct("VInt64");
43        if !self.is_unknown {
44            t.field("value", &self.value);
45        } else {
46            t.field("value", &"Unknown");
47        }
48        t.field("memory", &format!("{}", self));
49        t.finish()
50    }
51}
52
53impl Deref for VInt64 {
54    type Target = u64;
55    fn deref(&self) -> &Self::Target {
56        &self.value
57    }
58}
59impl VInt64 {
60    /// Create a VInt64 from an already encoded u64 value.
61    pub const fn from_encoded(enc: u64) -> Self {
62        if enc == 0xFF {
63            Self {
64                value: 127,
65                is_unknown: true,
66            }
67        } else if enc == 0x407F {
68            Self {
69                value: 127,
70                is_unknown: false,
71            }
72        } else {
73            Self {
74                value: enc & (u64::MAX >> (enc.leading_zeros() + 1)),
75                is_unknown: false,
76            }
77        }
78    }
79
80    /// Create a VInt64 representing an unknown size.
81    pub const fn new_unknown() -> Self {
82        Self {
83            value: 127,
84            is_unknown: true,
85        }
86    }
87
88    /// Create a VInt64 from a u64 value.
89    pub const fn new(value: u64) -> Self {
90        Self {
91            value,
92            is_unknown: false,
93        }
94    }
95
96    /// Create a VInt64 from an already encoded u64 value.
97    pub fn as_encoded(&self) -> u64 {
98        if self.is_unknown {
99            return 0xFF;
100        }
101        if self.value == 127 {
102            return 0x407F;
103        }
104
105        let size = VInt64::encode_size(self.value);
106        let mut sbuf = [0u8; 8];
107        let slice = &mut sbuf[8 - size..];
108        slice.copy_from_slice(&self.value.to_be_bytes()[8 - size..]);
109        slice[0] |= 1u8 << (8 - size);
110        u64::from_be_bytes(sbuf)
111    }
112
113    /// Get the size in bytes of the encoded representation of a u64 value.
114    pub const fn encode_size(value: u64) -> usize {
115        let leading_zeros = value.leading_zeros() as usize;
116        let total_bits = 64 - leading_zeros;
117        if total_bits == 0 {
118            1
119        } else {
120            (total_bits + 6).div_euclid(7)
121        }
122    }
123}
124
125impl ReadFrom for VInt64 {
126    fn read_from<R: std::io::Read>(r: &mut R) -> crate::Result<Self> {
127        let mut first_byte_buf = [0u8; 1];
128        r.read_exact(&mut first_byte_buf)?;
129        let first_byte = first_byte_buf[0];
130        if first_byte == 0xFF {
131            return Ok(VInt64 {
132                value: 127,
133                is_unknown: true,
134            });
135        }
136
137        let leading_zeros = first_byte.leading_zeros() as usize;
138        if leading_zeros >= 8 {
139            return Err(crate::error::Error::InvalidVInt);
140        }
141
142        if leading_zeros == 0 {
143            Ok(VInt64 {
144                value: (first_byte & 0b0111_1111) as u64,
145                is_unknown: false,
146            })
147        } else {
148            let mut buf = [0u8; 8];
149            let read_buf = &mut buf[8 - leading_zeros..];
150            r.read_exact(read_buf)?;
151            if leading_zeros != 7 {
152                buf[8 - leading_zeros - 1] = first_byte & (0xFF >> (leading_zeros + 1));
153            }
154            Ok(VInt64 {
155                value: u64::from_be_bytes(buf),
156                is_unknown: false,
157            })
158        }
159    }
160}
161
162#[cfg(feature = "tokio")]
163#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
164impl crate::io::tokio_impl::AsyncReadFrom for VInt64 {
165    async fn async_read_from<R: tokio::io::AsyncRead + Unpin>(r: &mut R) -> crate::Result<Self> {
166        let mut first_byte_buf = [0u8; 1];
167        tokio::io::AsyncReadExt::read_exact(r, &mut first_byte_buf).await?;
168        let first_byte = first_byte_buf[0];
169        if first_byte == 0xFF {
170            return Ok(VInt64 {
171                value: 127,
172                is_unknown: true,
173            });
174        }
175
176        let leading_zeros = first_byte.leading_zeros() as usize;
177        if leading_zeros >= 8 {
178            return Err(crate::error::Error::InvalidVInt);
179        }
180
181        if leading_zeros == 0 {
182            Ok(VInt64 {
183                value: (first_byte & 0b0111_1111) as u64,
184                is_unknown: false,
185            })
186        } else {
187            let mut buf = [0u8; 8];
188            let read_buf = &mut buf[8 - leading_zeros..];
189            tokio::io::AsyncReadExt::read_exact(r, read_buf).await?;
190            if leading_zeros != 7 {
191                buf[8 - leading_zeros - 1] = first_byte & (0xFF >> (leading_zeros + 1));
192            }
193            Ok(VInt64 {
194                value: u64::from_be_bytes(buf),
195                is_unknown: false,
196            })
197        }
198    }
199}
200
201impl Decode for VInt64 {
202    fn decode(buf: &mut &[u8]) -> crate::Result<Self> {
203        if !buf.has_remaining() {
204            return Err(Error::OutOfBounds);
205        }
206        let first_byte = u8::decode(buf)?;
207        if first_byte == 0 {
208            return Err(Error::InvalidVInt);
209        }
210        if first_byte == 0xFF {
211            return Ok(VInt64 {
212                value: 127,
213                is_unknown: true,
214            });
215        }
216        let leading_zeros = first_byte.leading_zeros() as usize;
217
218        if leading_zeros == 0 {
219            Ok(VInt64 {
220                value: (first_byte & 0b0111_1111) as u64,
221                is_unknown: false,
222            })
223        } else {
224            if buf.remaining() < leading_zeros {
225                return Err(Error::OutOfBounds);
226            }
227            let mut bytes = [0u8; 8];
228            let read_buf = &mut bytes[8 - leading_zeros..];
229            read_buf.copy_from_slice(buf.slice(leading_zeros));
230
231            if leading_zeros != 7 {
232                bytes[8 - leading_zeros - 1] = first_byte & (0xFF >> (leading_zeros + 1));
233            }
234            buf.advance(leading_zeros);
235            Ok(VInt64 {
236                value: u64::from_be_bytes(bytes),
237                is_unknown: false,
238            })
239        }
240    }
241}
242
243impl Encode for VInt64 {
244    fn encode<B: BufMut>(&self, buf: &mut B) -> crate::Result<()> {
245        if self.is_unknown {
246            buf.append_slice(&[0xFF]);
247            return Ok(());
248        }
249        if self.value == 127 {
250            buf.append_slice(&[0x40, 0x7F]);
251            return Ok(());
252        }
253
254        let size = VInt64::encode_size(self.value);
255        let mut sbuf = [0u8; 8];
256        let slice = &mut sbuf[8 - size..];
257        slice.copy_from_slice(&self.value.to_be_bytes()[8 - size..]);
258        slice[0] |= 1u8 << (8 - size);
259        buf.append_slice(slice);
260        Ok(())
261    }
262}
263
264#[cfg(test)]
265mod tests {
266    use crate::functional::{Decode, Encode};
267
268    use super::*;
269    use std::convert::TryInto;
270
271    #[test]
272    fn test_encode_size() {
273        let test_pair = [
274            (vec![0b1000_0000], 0),
275            (vec![0b1000_0001], 1),
276            (vec![0b0100_0000, 0xFF], 0xFF),
277            (vec![0b0100_0001, 0xFF], 0b1_1111_1111),
278            (vec![0b0111_1111, 0xFF], 0b11_1111_1111_1111),
279            (vec![0b0010_0000, 0b0111_1111, 0xFF], 0b111_1111_1111_1111),
280            (vec![0b0010_0000, 0xFF, 0xFF], 0xFFFF),
281            (vec![0b0011_1111, 0xFF, 0xFF], 0b1_1111_1111_1111_1111_1111),
282            (
283                vec![1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
284                0xFF_FFFF_FFFF_FFFF,
285            ),
286        ];
287        for (encoded, val) in test_pair {
288            assert_eq!(VInt64::encode_size(val), encoded.len());
289        }
290    }
291
292    #[test]
293    fn test_encode() {
294        let test_pair = [
295            (vec![0b1000_0000], 0),
296            (vec![0b1000_0001], 1),
297            (vec![0b0100_0000, 0xFF], 0xFF),
298            (vec![0b0100_0001, 0xFF], 0b1_1111_1111),
299            (vec![0b0111_1111, 0xFF], 0b11_1111_1111_1111),
300            (vec![0b0010_0000, 0b0111_1111, 0xFF], 0b111_1111_1111_1111),
301            (vec![0b0010_0000, 0xFF, 0xFF], 0xFFFF),
302            (vec![0b0011_1111, 0xFF, 0xFF], 0b1_1111_1111_1111_1111_1111),
303            (
304                vec![1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
305                0xFF_FFFF_FFFF_FFFF,
306            ),
307        ];
308        for (encoded, val) in test_pair {
309            let v = VInt64 {
310                value: val,
311                is_unknown: false,
312            };
313            let mut out = vec![];
314            v.encode(&mut out).unwrap();
315            assert_eq!(encoded, out);
316
317            let encoded_num = v.as_encoded();
318            let mut enc8 = vec![0u8; 8 - encoded.len()];
319            enc8.extend_from_slice(&encoded);
320            let encoded_from = u64::from_be_bytes(enc8.try_into().unwrap());
321            assert_eq!(encoded_num, encoded_from);
322        }
323    }
324
325    #[test]
326    fn test_decode() {
327        let test_pair = [
328            (vec![0b1000_0000], 0),
329            (vec![0b1000_0001], 1),
330            (vec![0b0100_0000, 0xFF], 0xFF),
331            (vec![0b0100_0001, 0xFF], 0b1_1111_1111),
332            (vec![0b0111_1111, 0xFF], 0b11_1111_1111_1111),
333            (vec![0b0010_0000, 0b0111_1111, 0xFF], 0b111_1111_1111_1111),
334            (vec![0b0010_0000, 0xFF, 0xFF], 0xFFFF),
335            (vec![0b0011_1111, 0xFF, 0xFF], 0b1_1111_1111_1111_1111_1111),
336            (
337                vec![1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
338                0xFF_FFFF_FFFF_FFFF,
339            ),
340        ];
341        for (encoded, val) in test_pair {
342            // test read
343            let mut c = std::io::Cursor::new(encoded.clone());
344            let vint = VInt64::read_from(&mut c).unwrap();
345            assert_eq!(*vint, val);
346
347            // test decode
348            let ecoded2 = encoded.clone();
349            let mut slice_encoded2 = &ecoded2[..];
350            let vint_decoded = VInt64::decode(&mut slice_encoded2).unwrap();
351            assert_eq!(*vint_decoded, val);
352
353            // test from_encoded
354            let mut enc8 = vec![0u8; 8 - encoded.len()];
355            enc8.extend_from_slice(&encoded);
356            let v = VInt64::from_encoded(u64::from_be_bytes(enc8.try_into().unwrap()));
357            assert_eq!(*v, val);
358        }
359    }
360
361    #[test]
362    fn test_unknown() {
363        let v1 = VInt64::read_from(&mut std::io::Cursor::new(vec![0xFF])).unwrap();
364        let vv1 = VInt64::from_encoded(0xFF);
365        assert!(v1.is_unknown);
366        assert!(vv1.is_unknown);
367
368        let v2 = VInt64::read_from(&mut std::io::Cursor::new(vec![0x80])).unwrap();
369        let vv2 = VInt64::from_encoded(0x80);
370
371        assert!(!v2.is_unknown);
372        assert!(!vv2.is_unknown);
373
374        let v3 = VInt64::read_from(&mut std::io::Cursor::new(vec![0x40, 0x7F])).unwrap();
375        let vv3 = VInt64::from_encoded(0x407F);
376        assert_eq!(*v3, 127);
377        assert_eq!(*vv3, 127);
378
379        assert_ne!(VInt64::new(127), VInt64::new_unknown());
380        assert_eq!(VInt64::new(127).as_encoded(), 0x407F);
381    }
382}
383
384/// EBML element header, consisting of an ID and a size.
385#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
386pub struct Header {
387    /// EBML ID of the element.
388    pub id: VInt64,
389    /// Size of the element's data, excluding the header itself.
390    pub size: VInt64,
391}
392
393impl ReadFrom for Header {
394    fn read_from<R: std::io::Read>(reader: &mut R) -> crate::Result<Self> {
395        let id = VInt64::read_from(reader)?;
396        let size = VInt64::read_from(reader)?;
397        Ok(Self { id, size })
398    }
399}
400
401#[cfg(feature = "tokio")]
402#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
403impl crate::io::tokio_impl::AsyncReadFrom for Header {
404    async fn async_read_from<R: tokio::io::AsyncRead + Unpin>(r: &mut R) -> crate::Result<Self> {
405        let id = VInt64::async_read_from(r).await?;
406        let size = VInt64::async_read_from(r).await?;
407        Ok(Self { id, size })
408    }
409}
410
411impl Decode for Header {
412    fn decode(buf: &mut &[u8]) -> crate::Result<Self> {
413        let id = VInt64::decode(buf)?;
414        let size = VInt64::decode(buf)?;
415        Ok(Self { id, size })
416    }
417}
418
419impl Encode for Header {
420    fn encode<B: BufMut>(&self, buf: &mut B) -> crate::Result<()> {
421        self.id.encode(buf)?;
422        self.size.encode(buf)?;
423        Ok(())
424    }
425}