1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
use crate::*;
const SMALL_ICON_LEN: usize = 3*3*8;
const LARGE_ICON_LEN: usize = 8*8*8;
pub fn parse_metadata(bytecode: &[u8]) -> Option<ProgramMetadata> {
MetadataParser::from_bytecode(bytecode).parse()
}
pub struct ProgramMetadata {
pub name: Option<String>,
pub version: Option<String>,
pub authors: Option<Vec<String>>,
pub description: Option<String>,
pub bg_colour: Option<Colour>,
pub fg_colour: Option<Colour>,
pub small_icon: Option<[u8; SMALL_ICON_LEN]>,
pub large_icon: Option<[u8; LARGE_ICON_LEN]>,
}
struct MetadataParser<'a> {
bytecode: &'a [u8],
}
impl<'a> MetadataParser<'a> {
pub fn from_bytecode(bytecode: &'a [u8]) -> Self {
Self { bytecode }
}
pub fn parse(self) -> Option<ProgramMetadata> {
// Verify metadata identifier.
let identifier = self.vec(0x00, 10);
if identifier != &[0x41,0x00,0x18,0x42,0x45,0x44,0x52,0x4F,0x43,0x4B] {
return None;
}
let (name, version) = if let Some(pointer) = self.pointer(0x0a) {
let string = self.string(pointer);
if let Some((name, version)) = string.split_once('/') {
(Some(name.trim().to_string()), Some(version.trim().to_string()))
} else {
(Some(string.trim().to_string()), None)
}
} else {
(None, None)
};
let authors = self.pointer(0x0c).map(|p| {
self.string(p).lines().map(|s| s.trim().to_string()).collect()
});
let description = self.pointer(0x0e).map(|p| self.string(p));
let bg_colour = self.pointer(0x10).map(|p| self.colour(p));
let fg_colour = self.pointer(0x12).map(|p| self.colour(p));
let small_icon = if let Some(pointer) = self.pointer(0x14) {
let vec = self.vec(pointer, SMALL_ICON_LEN);
Some(vec.try_into().unwrap())
} else {
None
};
let large_icon = if let Some(pointer) = self.pointer(0x16) {
let vec = self.vec(pointer, LARGE_ICON_LEN);
Some(vec.try_into().unwrap())
} else {
None
};
let metadata = ProgramMetadata {
name, version, authors, description,
bg_colour, fg_colour, small_icon, large_icon,
};
return Some(metadata);
}
fn byte(&self, address: usize) -> u8 {
match self.bytecode.get(address) {
Some(byte) => *byte,
None => 0,
}
}
fn double(&self, address: usize) -> u16 {
u16::from_be_bytes([
self.byte(address),
self.byte(address + 1),
])
}
fn pointer(&self, address: usize) -> Option<usize> {
match self.double(address) {
0 => None,
v => Some(v as usize),
}
}
fn vec(&self, address: usize, length: usize) -> Vec<u8> {
let mut vec = Vec::new();
for i in 0..length {
vec.push(self.byte(address + i));
}
return vec;
}
fn string(&self, address: usize) -> String {
let mut i = address;
while self.byte(i) != 0 {
i += 1;
}
let slice = &self.bytecode[address..i];
String::from_utf8_lossy(slice).to_string()
}
fn colour(&self, address: usize) -> Colour {
let double = self.double(address);
let r = (double >> 8 & 0xf) as u8 * 17;
let g = (double >> 4 & 0xf) as u8 * 17;
let b = (double & 0xf) as u8 * 17;
Colour::from_rgb(r, g, b)
}
}
|