pub struct Metadata<'a> { program: &'a [u8], } impl<'a> Metadata<'a> { pub fn from(program: &'a [u8]) -> Option { if program.len() < 10 { return None; } let identifier = [0xE8,0x00,0x18,0x42,0x45,0x44,0x52,0x4F,0x43,0x4B]; match program[0..10] == identifier { true => Some(Self { program }), false => None, } } pub fn name(&self) -> Option { let pointer = self.get_pointer(0x000A)?; self.get_string(pointer) } pub fn authors(&self) -> Option> { let pointer = self.get_pointer(0x000C)?; let string = self.get_string(pointer)?; Some(string.lines().map(String::from).collect()) } pub fn description(&self) -> Option { let pointer = self.get_pointer(0x000E)?; self.get_string(pointer) } pub fn bg_colour(&self) -> Option { let pointer = self.get_pointer(0x0010)?; let colour = self.get_pointer(pointer)?; Some(MetadataColour::from_double(colour)) } pub fn fg_colour(&self) -> Option { let pointer = self.get_pointer(0x0012)?; let colour = self.get_pointer(pointer)?; Some(MetadataColour::from_double(colour)) } pub fn small_icon(&self) -> Option> { let pointer = self.get_pointer(0x0014)?; self.get_icon(pointer, 72) } pub fn large_icon(&self) -> Option> { let pointer = self.get_pointer(0x0016)?; self.get_icon(pointer, 512) } fn get_byte(&self, address: u16) -> Option { self.program.get(address as usize).copied() } fn get_pointer(&self, address: u16) -> Option { let high = self.get_byte(address)?; let low = self.get_byte(address.checked_add(1)?)?; let pointer = u16::from_be_bytes([high, low]); if pointer != 0 { Some(pointer) } else { None } } fn get_string(&self, address: u16) -> Option { let start = address as usize; let mut end = address as usize; loop { match self.program.get(end) { Some(0) => break, Some(_) => end += 1, None => return None, } } let vec = self.program[start..end].to_vec(); String::from_utf8(vec).ok() } fn get_icon(&self, address: u16, length: usize) -> Option> { let address = address as usize; let data = &self.program[address..address+length]; match data.len() == length { true => Some(data.to_vec()), false => None, } } } pub struct MetadataColour { pub red: u8, pub green: u8, pub blue: u8, } impl MetadataColour { pub fn from_double(colour: u16) -> Self { let red = (colour & 0x0F00 >> 8) as u8 * 17; let green = (colour & 0x00F0 >> 4) as u8 * 17; let blue = (colour & 0x000F >> 0) as u8 * 17; Self { red, green, blue } } }