tinyvg_rs/
common.rs

1use std::io::Cursor;
2use byteorder::{LittleEndian, ReadBytesExt};
3use crate::{CoordinateRange, TinyVgParseError};
4
5#[derive(Debug, Copy, Clone)]
6pub struct Unit(pub f64);
7
8/// Unit may be 8, 16, or 32 bits, so we will advance the cursor conditionally.
9pub(crate) fn read_size(coordinate_range: &CoordinateRange, cursor: &mut Cursor<&[u8]>) -> Result<u32, TinyVgParseError> {
10    let res = match coordinate_range {
11        CoordinateRange::Reduced  => cursor.read_u8().map_err(|_| TinyVgParseError::InvalidHeader)? as u32,
12        CoordinateRange::Default  => cursor.read_u16::<LittleEndian>().map_err(|_| TinyVgParseError::InvalidHeader)? as u32,
13        CoordinateRange::Enhanced => cursor.read_u32::<LittleEndian>().map_err(|_| TinyVgParseError::InvalidHeader)?
14    };
15    Ok(res)
16}
17
18/// Page 4, VarUInt.
19/// This type is used to encode 32-bit unsigned integers while keeping the number of bytes low. It is encoded
20/// as a variable-sized integer that uses 7 bit per byte for integer bits and the 7th bit to encode that there
21/// are more bits available.
22pub(crate) fn read_variable_sized_unsigned_number(cursor: &mut Cursor<&[u8]>) -> Result<u64, TinyVgParseError> {
23    let mut count = 0u64;
24    let mut result = 0u64;
25    loop {
26        let byte = cursor.read_u8().map_err(|_| TinyVgParseError::InvalidHeader)?;
27        let val: u64 = (byte as u64 & 0x7F) << (7 * count);
28        result |= val;
29        if (byte & 0x80) == 0 {
30            break;
31        }
32        count += 1;
33    }
34
35    Ok(result)
36}
37
38
39pub(crate) fn read_unit(scale: u8, cursor: &mut Cursor<&[u8]>, coordinate_range: &CoordinateRange) -> Result<Unit, TinyVgParseError> {
40    let raw: i64;
41
42    match coordinate_range {
43        CoordinateRange::Default => raw = cursor.read_i16::<LittleEndian>().map_err(|_| TinyVgParseError::InvalidCommand)? as i64,
44        CoordinateRange::Reduced => raw = cursor.read_i8().map_err(|_| TinyVgParseError::InvalidCommand)? as i64,
45        CoordinateRange::Enhanced => raw = cursor.read_i32::<LittleEndian>().map_err(|_| TinyVgParseError::InvalidCommand)? as i64,
46    }
47    
48    let units_in_css_px: f64 = raw as f64 / (1 << scale) as f64;
49
50    Ok(Unit(units_in_css_px))
51}