woff2-no-std 0.3.4

WOFF2 decompression library
Documentation
use alloc::vec::Vec;
use bytes::BufMut;
use thiserror::Error;

use crate::buffer::{pad_to_multiple_of_four, SafeBuf};

mod bitmap;
mod composite;
mod parser;
mod simple;
mod triplet;

use bitmap::Bitmap;
pub(crate) use parser::decode_glyf_table;

#[derive(Error, Debug)]
pub enum GlyfDecoderError {
    #[error("Stream truncated")]
    Truncated,
    #[error("Composite glyph without bbox")]
    CompositeGlyphWithoutBbox,
    #[error("Extra Data")]
    ExtraData,
}

impl From<crate::buffer::TruncatedError> for GlyfDecoderError {
    fn from(_: crate::buffer::TruncatedError) -> Self {
        GlyfDecoderError::Truncated
    }
}

struct Woff2GlyfDecoder<'a> {
    num_glyphs: u16,
    n_contour_stream: &'a [u8],
    n_points_stream: &'a [u8],
    flag_stream: &'a [u8],
    glyph_stream: &'a [u8],
    composite_stream: &'a [u8],
    bbox_bitmap: Bitmap<'a>,
    bbox_stream: &'a [u8],
    instruction_stream: &'a [u8],
    overlap_bitmap: Option<Bitmap<'a>>,
    trailer: &'a [u8],
    index_format: u16,
}

impl<'a> Woff2GlyfDecoder<'a> {
    fn has_read_all(&self) -> bool {
        self.n_contour_stream.is_empty()
            && self.n_points_stream.is_empty()
            && self.flag_stream.is_empty()
            && self.glyph_stream.is_empty()
            && self.composite_stream.is_empty()
            && self.bbox_stream.is_empty()
            && self.instruction_stream.is_empty()
            && self.trailer.is_empty()
    }

    fn parse_next_glyph(
        &mut self,
        glyph_index: u16,
        output_vector: &mut Vec<u8>,
    ) -> Result<(), GlyfDecoderError> {
        let number_of_contours = SafeBuf::try_get_i16(&mut self.n_contour_stream)?;
        match number_of_contours {
            0 => Ok(()),
            num if num > 0 => {
                self.parse_simple_glyph(number_of_contours, glyph_index, output_vector)
            }
            _ => self.parse_composite_glyph(glyph_index, output_vector),
        }
    }

    fn parse_all_glyphs(&mut self) -> Result<(Vec<u8>, Vec<u8>), GlyfDecoderError> {
        let loca_uses_u32 = self.index_format > 0;
        let loca_entry_size = if loca_uses_u32 { 4 } else { 2 };
        let mut output_glyf_table = Vec::new();
        let mut output_loca_table =
            Vec::with_capacity(usize::from(self.num_glyphs + 1) * loca_entry_size);

        let write_loca_entry = |loca_table: &mut Vec<u8>, glyf_len: usize| {
            if loca_uses_u32 {
                loca_table.put_u32(glyf_len.try_into().unwrap());
            } else {
                loca_table.put_u16((glyf_len / 2).try_into().unwrap());
            }
        };

        for glyph_index in 0..self.num_glyphs {
            write_loca_entry(&mut output_loca_table, output_glyf_table.len());
            self.parse_next_glyph(glyph_index, &mut output_glyf_table)?;
            pad_to_multiple_of_four(&mut output_glyf_table);
        }

        if !loca_uses_u32 && output_glyf_table.len() % 2 == 1 {
            output_glyf_table.put_u8(0);
        }
        write_loca_entry(&mut output_loca_table, output_glyf_table.len());

        Ok((output_glyf_table, output_loca_table))
    }
}