diff options
Diffstat (limited to 'src/components/metadata.rs')
-rw-r--r-- | src/components/metadata.rs | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/components/metadata.rs b/src/components/metadata.rs new file mode 100644 index 0000000..5c2361b --- /dev/null +++ b/src/components/metadata.rs @@ -0,0 +1,104 @@ +pub struct Metadata<'a> { + program: &'a [u8], +} + +impl<'a> Metadata<'a> { + pub fn from(program: &'a [u8]) -> Option<Self> { + 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<String> { + let pointer = self.get_pointer(0x000A)?; + self.get_string(pointer) + } + + pub fn authors(&self) -> Option<Vec<String>> { + let pointer = self.get_pointer(0x000C)?; + let string = self.get_string(pointer)?; + Some(string.lines().map(String::from).collect()) + } + + pub fn description(&self) -> Option<String> { + let pointer = self.get_pointer(0x000E)?; + self.get_string(pointer) + } + + pub fn bg_colour(&self) -> Option<MetadataColour> { + let pointer = self.get_pointer(0x0010)?; + let colour = self.get_pointer(pointer)?; + Some(MetadataColour::from_double(colour)) + } + + pub fn fg_colour(&self) -> Option<MetadataColour> { + let pointer = self.get_pointer(0x0012)?; + let colour = self.get_pointer(pointer)?; + Some(MetadataColour::from_double(colour)) + } + + pub fn small_icon(&self) -> Option<Vec<u8>> { + let pointer = self.get_pointer(0x0014)?; + self.get_icon(pointer, 72) + } + + pub fn large_icon(&self) -> Option<Vec<u8>> { + let pointer = self.get_pointer(0x0016)?; + self.get_icon(pointer, 512) + } + + fn get_byte(&self, address: u16) -> Option<u8> { + self.program.get(address as usize).copied() + } + + fn get_pointer(&self, address: u16) -> Option<u16> { + 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<String> { + 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<Vec<u8>> { + 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 } + } +} |