//! Structures used by Marathon's Map format's terminal definitions. use crate::durandal::{err::*, text::*}; use bitflags::bitflags; /// Reads a `Group`. pub fn read_group(b: &[u8], text: &[u8]) -> ResultS { read_data! { 12, BE in b => flags = u16[0]; ttype = u16[2]; pdata = u16[4]; start = u16[6] usize; size = u16[8] usize; lines = u16[10]; } let text = ok!(text.get(start..start + size), "not enough data")?; let text = mac_roman_cstr(text)?; let flags = flag_ok!(GroupFlags, flags)?; let ttype = match ttype { 0 => GroupType::Logon(pdata), 1 => GroupType::Unfinished, 2 => GroupType::Success, 3 => GroupType::Failure, 4 => GroupType::Info, 5 => GroupType::End, 6 => GroupType::TeleInter(pdata), 7 => GroupType::TeleIntra(pdata), 8 => GroupType::Checkpoint(pdata), 9 => GroupType::Sound(pdata), 10 => GroupType::Movie(pdata), 11 => GroupType::Track(pdata), 12 => GroupType::Pict(pdata), 13 => GroupType::Logoff(pdata), 14 => GroupType::Camera(pdata), 15 => GroupType::Static(pdata), 16 => GroupType::Tag(pdata), n => return Err(ReprError::new(n).into()), }; Ok(Group{flags, ttype, lines, text}) } /// Reads a `Face`. pub fn read_face(b: &[u8]) -> ResultS { read_data! { 6, BE in b => start = u16[0] usize; face = u16[2]; color = u16[4]; } Ok(Face{start, face, color}) } /// Reads a `term` chunk. pub fn read_term(b: &[u8]) -> ResultS<(Terminal, usize)> { const SIZE_GROUP: usize = 12; const SIZE_FACE: usize = 6; read_data! { 10, BE in b => end = u16[0] usize; encoded = u16[2]; lines = u16[4]; group_n = u16[6] usize; face_n = u16[8] usize; } let encoded = encoded != 0; let mut groups = Vec::with_capacity(group_n); let mut faces = Vec::with_capacity(face_n); let mut p = 10; let text_st = p + SIZE_GROUP * group_n + SIZE_FACE * face_n; let text = ok!(b.get(text_st..end), "bad offset")?; let text = if encoded { fuck_string(text) } else { text.to_vec() }; for _ in 0..group_n { groups.push(read_group(ok!(b.get(p..), "not enough data")?, &text)?); p += SIZE_GROUP; } for _ in 0..face_n { faces.push(read_face(ok!(b.get(p..), "not enough data")?)?); p += SIZE_FACE; } Ok((Terminal{lines, groups, faces}, end)) } /// A terminal definition, with collections of groups and faces. #[derive(Debug, PartialEq, serde::Serialize)] pub struct Terminal { pub lines: u16, pub groups: Vec, pub faces: Vec, } /// A text face. #[derive(Debug, PartialEq, serde::Serialize)] pub struct Face { pub start: usize, pub face: u16, pub color: u16, } /// A terminal command grouping. #[derive(Debug, PartialEq, serde::Serialize)] pub struct Group { pub flags: GroupFlags, pub ttype: GroupType, pub lines: u16, pub text: String, } /// The command of a `Group`. #[derive(Debug, PartialEq, serde::Serialize)] pub enum GroupType { Logon(u16), Unfinished, Success, Failure, Info, End, TeleInter(u16), TeleIntra(u16), Checkpoint(u16), Sound(u16), Movie(u16), Track(u16), Pict(u16), Logoff(u16), Camera(u16), Static(u16), Tag(u16), } bitflags! { /// Flags for `Group`. #[derive(serde::Serialize)] pub struct GroupFlags: u16 { const DrawOnRight = 1; const DrawCenter = 1 << 1; } } // EOF