aboutsummaryrefslogtreecommitdiff
path: root/ebml/src/read.rs
blob: 7431683b76e9b832cb94759fdfba3204332ab959 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::io::{Read, Seek};
use anyhow::Result;

trait ReadAndSeek: Read + Seek {}
impl<T: Read + Seek> ReadAndSeek for T {}

pub struct EbmlReader {
    inner: Box<dyn ReadAndSeek>,
    pub position: usize,
}

pub trait EbmlRead: Sized {
    fn read(r: &mut EbmlReader) -> Result<Self>;
}

impl EbmlReader {
    pub fn new<T: Seek + Read + 'static>(inner: T) -> Self {
        Self {
            inner: Box::new(inner),
            position: 0,
        }
    }

    pub fn read_byte(&mut self) -> Result<u8> {
        let mut b = [0u8];
        self.inner.read_exact(&mut b)?;
        self.position += 1;
        Ok(b[0])
    }
    pub fn read_buf(&mut self, size: impl Into<usize>) -> Result<Vec<u8>> {
        let size = size.into();
        let mut b = vec![0u8; size];
        self.inner.read_exact(&mut b)?;
        self.position += size;
        Ok(b)
    }
    pub fn read_vint_len(&mut self) -> Result<(u64, usize)> {
        let s = self.read_byte()?;
        let len = s.leading_zeros() + 1;
        let mut value = s as u64;
        value -= 1 << (8 - len);
        for _ in 0..(len - 1) {
            value <<= 8;
            value += self.read_byte()? as u64;
        }
        Ok((value, len as usize))
    }
    pub fn read_vint(&mut self) -> Result<u64> {
        Ok(self.read_vint_len()?.0)
    }
    pub fn read_utf8(&mut self, size: impl Into<usize>) -> Result<String> {
        let b = self.read_buf(size)?;
        Ok(String::from_utf8(b)?)
    }

    pub fn read_tag_id(&mut self) -> Result<u64> {
        let (value, len) = self.read_vint_len()?;
        Ok(value + (1 << (7 * len)))
    }
}

#[derive(Debug, Clone, Copy)]
pub enum EbmlSize {
    Exact(usize),
    Unknown,
}
impl EbmlSize {
    #[rustfmt::skip]
    pub fn from_vint((value, len): (u64, usize)) -> EbmlSize {
        match len {
            1 => if value == ((1 << (7))     - 1) { return Self::Unknown; },
            2 => if value == ((1 << (7 * 2)) - 1) { return Self::Unknown; },
            3 => if value == ((1 << (7 * 3)) - 1) { return Self::Unknown; },
            4 => if value == ((1 << (7 * 4)) - 1) { return Self::Unknown; },
            5 => if value == ((1 << (7 * 5)) - 1) { return Self::Unknown; },
            6 => if value == ((1 << (7 * 6)) - 1) { return Self::Unknown; },
            7 => if value == ((1 << (7 * 7)) - 1) { return Self::Unknown; },
            8 => if value == ((1 << (7 * 8)) - 1) { return Self::Unknown; },
            _ => {},
        }
        Self::Exact(len)
    }
}
impl Into<usize> for EbmlSize {
    fn into(self) -> usize {
        match self {
            EbmlSize::Exact(s) => s,
            EbmlSize::Unknown => panic!("unknown size, where it should have been known"),
        }
    }
}