resource-fork-types 0.1.1

Support for reading common resource fork types in rust
Documentation
use binrw::{binread, BinRead, BinReaderExt};
use resource_fork::Resource;

pub fn roman_char(input: u8) -> Option<char> {
    if input == 0 {
        return None;
    }

    let input = [input];

    encoding_rs::MACINTOSH
        .decode(&input)
        .0
        .to_string()
        .chars()
        .next()
}

#[binread]
#[derive(Debug)]
pub struct LongArray<T: BinRead + 'static>
where
    for<'a> <T as BinRead>::Args<'a>: Default + Clone,
{
    #[br(temp)]
    count: u16,

    #[br(count(count))]
    pub(crate) items: Vec<T>,
}

pub fn long_list<T: BinRead>(input: LongArray<T>) -> Vec<T>
where
    for<'a> <T as BinRead>::Args<'a>: Default + Clone,
{
    input.items
}

#[binread]
pub(crate) struct LongArrayPlusOne<T: BinRead + 'static>
where
    for<'a> <T as BinRead>::Args<'a>: Default + Clone,
{
    #[br(temp)]
    last_index: u16,

    #[br(temp, calc(if last_index == 0xFFFF { 0 } else {last_index as usize +1} ))]
    count: usize,

    #[br(count(count))]
    pub(crate) items: Vec<T>,
}

pub(crate) fn long_list_plus_one<T: BinRead>(input: LongArrayPlusOne<T>) -> Vec<T>
where
    for<'a> <T as BinRead>::Args<'a>: Default + Clone,
{
    input.items
}

#[derive(BinRead)]
#[br(import_raw(args: <T as BinRead>::Args<'_>))]
enum ListItem<T: BinRead> {
    #[br(magic(0u8))]
    None,
    Some(#[br(args_raw = args)] T),
}

pub(crate) struct NullTerminatedList<T: BinRead>
where
    for<'a> <T as BinRead>::Args<'a>: Clone,
{
    items: Vec<T>,
}

impl<T: BinRead> BinRead for NullTerminatedList<T>
where
    for<'a> <T as BinRead>::Args<'a>: Clone,
{
    type Args<'a> = <T as BinRead>::Args<'a>;

    fn read_options<R: std::io::Read + std::io::Seek>(
        reader: &mut R,
        endian: binrw::Endian,
        args: Self::Args<'_>,
    ) -> binrw::BinResult<Self> {
        let mut items = Vec::new();

        loop {
            match reader.read_type_args::<ListItem<T>>(endian, args.clone())? {
                ListItem::None => return Ok(Self { items }),
                ListItem::Some(item) => items.push(item),
            }
        }
    }
}

pub(crate) fn null_terminated_list<T: binrw::BinRead>(list: NullTerminatedList<T>) -> Vec<T>
where
    for<'a> <T as BinRead>::Args<'a>: Clone,
{
    list.items
}

#[binread]
pub(crate) struct LengthPrefixedBuffer {
    #[br(temp)]
    len: u8,

    #[br(count(len))]
    contents: Vec<u8>,
}

impl From<LengthPrefixedBuffer> for Vec<u8> {
    fn from(val: LengthPrefixedBuffer) -> Self {
        val.contents
    }
}

#[derive(Debug, Copy, Clone, BinRead, Resource)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[resource(code = "RECT")]
#[br(big)]
pub struct Rect {
    pub top: i16,
    pub left: i16,
    pub bottom: i16,
    pub right: i16,
}

impl Rect {
    pub fn width(&self) -> i32 {
        self.right as i32 - self.left as i32
    }

    pub fn height(&self) -> i32 {
        self.bottom as i32 - self.top as i32
    }
}

#[derive(Debug, Copy, Clone, BinRead, Resource)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[resource(code = "PNT ")]
pub struct Point {
    pub x: i16,
    pub y: i16,
}