1use crate::{
2 core::{
3 result::Result,
4 sa::{self, Position, SymbolArt, SymbolArtLayer},
5 symbol,
6 },
7 parser::decode,
8};
9
10pub fn parse(bytes: impl Into<Box<[u8]>>) -> Result<impl SymbolArt + std::fmt::Debug> {
12 let body = get_body(bytes.into())?;
13 Payload::parse(&body)
14}
15
16fn get_body(mut bytes: Box<[u8]>) -> Result<Box<[u8]>> {
18 let compression = decode::validate_format(&bytes)?;
19 let (_, body) = bytes.split_at_mut(4);
20
21 decode::decrypt(body);
22 match compression {
23 decode::Compression::None => Ok(Box::from(body)),
24 decode::Compression::Compressed => decode::decompress(body),
25 }
26}
27
28#[derive(Debug, Clone, PartialEq)]
30pub struct Payload {
31 header: Header,
33 layers: Vec<Layer>,
35 name: Vec<u16>,
37}
38
39impl Payload {
40 pub fn parse(bytes: &[u8]) -> Result<Self> {
42 let header = Header::parse(&bytes[0..std::mem::size_of::<Header>()])?;
43 let layers = Layers::parse(&bytes[std::mem::size_of::<Header>()..])?.into();
44 let name = Self::parse_name(bytes, &header)?;
45
46 Ok(Self {
47 header,
48 layers,
49 name,
50 })
51 }
52
53 fn parse_name(bytes: &[u8], header: &Header) -> Result<Vec<u16>> {
55 let size_of_header = std::mem::size_of::<Header>();
56 let size_of_layer = std::mem::size_of::<Layer>();
57 let start = size_of_header + size_of_layer * header.layers() as usize;
58
59 let name_bytes = bytes[usize::min(start, bytes.len())..]
60 .chunks_exact(2)
61 .take(13) .map(|b| u16::from_le_bytes(b.try_into().unwrap()))
63 .collect::<Vec<_>>();
64
65 Ok(name_bytes)
66 }
67}
68
69const HEADER_SIZE_TEAM_FLAG: u8 = 0x40;
70const HEADER_SIZE_NORMAL: u8 = 0x80;
71
72impl SymbolArt for Payload {
73 type Layer = Layer;
74
75 fn author_id(&self) -> u32 {
76 self.header.author_id
77 }
78
79 fn height(&self) -> u8 {
80 match self.header.height {
81 HEADER_SIZE_NORMAL => 96,
82 HEADER_SIZE_TEAM_FLAG => 32,
83 _ => panic!("Invalid height having: {}", self.header.height),
84 }
85 }
86
87 fn width(&self) -> u8 {
88 match self.header.height {
89 HEADER_SIZE_NORMAL => 193,
90 HEADER_SIZE_TEAM_FLAG => 32,
91 _ => panic!("Invalid width having: {}", self.header.height),
92 }
93 }
94
95 fn layers(&self) -> Vec<Layer> {
96 self.layers.clone()
97 }
98
99 fn name(&self) -> String {
100 String::from_utf16_lossy(&self.name)
101 }
102}
103
104#[derive(Debug, Clone, PartialEq)]
106pub struct Header {
107 pub(super) author_id: u32,
109 pub(super) layers: u8,
111 pub(super) height: u8,
113 pub(super) width: u8,
115 pub(super) sound_effect: u8,
117}
118
119impl Header {
120 pub(super) fn parse(bytes: &[u8]) -> Result<Self> {
122 Ok(Header {
123 author_id: u32::from_be_bytes(bytes[0..4].try_into().unwrap()),
124 layers: bytes[4],
125 height: bytes[5],
126 width: bytes[6],
127 sound_effect: bytes[7],
128 })
129 }
130
131 pub(super) fn layers(&self) -> u8 {
132 self.layers
133 }
134}
135
136pub struct Layers {
138 layers: Vec<Layer>,
139}
140
141impl Layers {
142 pub(super) fn parse(bytes: &[u8]) -> Result<Self> {
144 let layers = bytes
145 .chunks_exact(std::mem::size_of::<Layer>())
146 .map(Layer::parse)
147 .collect::<Result<Vec<_>>>()?;
148
149 Ok(Self { layers })
150 }
151}
152
153impl From<Layers> for Vec<Layer> {
154 fn from(layers: Layers) -> Self {
155 layers.layers
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Copy)]
161pub struct Layer {
162 pub(super) top_left: Position,
164 pub(super) bottom_left: Position,
166 pub(super) top_right: Position,
168 pub(super) bottom_right: Position,
170 pub(super) is_hidden: bool,
172 pub(super) symbol_id: u16,
174 pub(super) alpha: u8,
176 pub(super) color_r: u8,
178 pub(super) color_g: u8,
180 pub(super) color_b: u8,
182}
183
184const LAYER_IS_HIDDEN: u32 = 0b10000000000000000000000000000000;
186const MASK_SYMBOL_ID: u32 = 0b01111111111000000000000000000000;
187const MASK_ALPHA: u32 = 0b00000000000111000000000000000000;
188const MASK_COLOR_R: u32 = 0b00000000000000000000000000111111;
189const MASK_COLOR_G: u32 = 0b00000000000000000000111111000000;
190const MASK_COLOR_B: u32 = 0b00000000000000111111000000000000;
191
192impl Layer {
193 fn parse(bytes: &[u8]) -> Result<Self> {
195 let top_left = Position::parse(&bytes[0..2])?;
196 let bottom_left = Position::parse(&bytes[2..4])?;
197 let top_right = Position::parse(&bytes[4..6])?;
198 let bottom_right = Position::parse(&bytes[6..8])?;
199
200 let layer_data = u32::from_le_bytes(bytes[8..12].try_into().unwrap());
201
202 Ok(Self {
203 top_left,
204 bottom_left,
205 top_right,
206 bottom_right,
207 is_hidden: Self::extract_is_hidden(layer_data),
208 symbol_id: Self::extract_symbol_id(layer_data),
209 alpha: Self::extract_alpha(layer_data),
210 color_r: Self::extract_color_r(layer_data),
211 color_g: Self::extract_color_g(layer_data),
212 color_b: Self::extract_color_b(layer_data),
213 })
214 }
215
216 fn extract_is_hidden(layer_data: u32) -> bool {
218 (layer_data & LAYER_IS_HIDDEN) != 0
219 }
220
221 fn extract_symbol_id(layer_data: u32) -> u16 {
223 ((layer_data & MASK_SYMBOL_ID) >> 21) as u16
224 }
225
226 fn extract_alpha(layer_data: u32) -> u8 {
228 ((layer_data & MASK_ALPHA) >> 18) as u8
229 }
230
231 fn extract_color_r(layer_data: u32) -> u8 {
233 (layer_data & MASK_COLOR_R) as u8
234 }
235
236 fn extract_color_g(layer_data: u32) -> u8 {
238 ((layer_data & MASK_COLOR_G) >> 6) as u8
239 }
240
241 fn extract_color_b(layer_data: u32) -> u8 {
243 ((layer_data & MASK_COLOR_B) >> 12) as u8
244 }
245}
246
247const ALPHA_FACTOR: u8 = 37;
253
254const COLOR_FACTOR: u8 = 4;
260
261impl SymbolArtLayer for Layer {
262 fn top_left(&self) -> Position {
263 self.top_left
264 }
265
266 fn bottom_left(&self) -> Position {
267 self.bottom_left
268 }
269
270 fn top_right(&self) -> Position {
271 self.top_right
272 }
273
274 fn bottom_right(&self) -> Position {
275 self.bottom_right
276 }
277
278 fn symbol(&self) -> symbol::Symbol {
279 symbol::Symbol::new(self.symbol_id.into())
280 }
281
282 fn color(&self) -> sa::Color {
283 let a = self.alpha.saturating_mul(ALPHA_FACTOR);
284 let r = self.color_r.saturating_mul(COLOR_FACTOR);
285 let g = self.color_g.saturating_mul(COLOR_FACTOR);
286 let b = self.color_b.saturating_mul(COLOR_FACTOR);
287 sa::Color::new(a, r, g, b)
288 }
289
290 fn is_hidden(&self) -> bool {
291 self.is_hidden
292 }
293}
294
295impl Position {
296 fn parse(bytes: &[u8]) -> Result<Self> {
298 Ok(Self {
299 x: bytes[0],
300 y: bytes[1],
301 })
302 }
303}
304
305#[cfg(test)]
306mod tests {
307 use super::*;
308 use crate::{
309 core::sa::Position,
310 test::{RAW_FILE, RAW_FILE_UNCOMPRESSED},
311 };
312
313 #[test]
314 fn test_get_body() {
315 let bytes = Box::from(RAW_FILE);
316 let body = get_body(bytes).unwrap();
317 assert_eq!(body.len(), 1682);
318 }
319
320 #[test]
321 fn test_parse() {
322 let bytes = Box::from(RAW_FILE);
323 let body = get_body(bytes).unwrap();
324 let payload = Payload::parse(&body).unwrap();
325
326 let expected_name = &[12394, 12363, 12383, 12373, 12435]; let expected = Payload {
328 header: Header {
329 author_id: 881302016,
330 layers: 104,
331 height: 128,
332 width: 193,
333 sound_effect: 3,
334 },
335 layers: vec![
336 Layer {
337 top_left: Position { x: 0, y: 0 },
338 bottom_left: Position { x: 0, y: 0 },
339 top_right: Position { x: 0, y: 0 },
340 bottom_right: Position { x: 0, y: 0 },
341 is_hidden: false,
342 symbol_id: 0,
343 alpha: 0,
344 color_r: 0,
345 color_g: 0,
346 color_b: 0,
347 };
348 104
349 ],
350 name: expected_name.to_vec(),
351 };
352
353 assert_eq!(payload.header, expected.header);
354 assert_eq!(payload.layers.len(), expected.layers.len());
355 assert_eq!(payload.name, expected.name);
356 }
357
358 #[test]
359 fn test_parse_uncompressed() {
360 let bytes = Box::from(RAW_FILE_UNCOMPRESSED);
361 let body = get_body(bytes).unwrap();
362 let payload = Payload::parse(&body).unwrap();
363
364 assert_eq!(
365 payload.name,
366 vec![84, 104, 97, 110, 107, 32, 121, 111, 117, 32, 33, 33]
367 );
368 }
369}