aseprite_loader/binary/
raw_frame.rs

1use nom::{
2    bytes::complete::{tag, take},
3    combinator::{all_consuming, complete},
4    multi::many1,
5    Parser,
6};
7
8use super::{
9    chunk::parse_chunks,
10    chunk::Chunk,
11    chunks::cel::CelChunk,
12    errors::{ParseError, ParseResult},
13    scalars::dword_size,
14    scalars::Word,
15    scalars::{parse_dword_as_usize, word},
16};
17
18#[derive(Debug)]
19pub struct RawFrame<'a> {
20    pub duration: Word,
21    pub chunks: Vec<Chunk<'a>>,
22}
23
24impl RawFrame<'_> {
25    pub fn cels(&self) -> impl Iterator<Item = &CelChunk<'_>> {
26        self.chunks.iter().filter_map(|chunk| {
27            if let Chunk::Cel(cel) = chunk {
28                Some(cel)
29            } else {
30                None
31            }
32        })
33    }
34}
35
36const FRAME_MAGIC_NUMBER: [u8; 2] = 0xF1FAu16.to_le_bytes();
37
38pub fn parse_frames(input: &[u8]) -> ParseResult<'_, Vec<RawFrame<'_>>> {
39    complete(all_consuming(many1(parse_rawframe))).parse(input)
40}
41
42pub fn parse_rawframe(input: &[u8]) -> ParseResult<'_, RawFrame<'_>> {
43    let (input, size) = dword_size(input, ParseError::InvalidFrameSize)?;
44    // FIXME handle underflows
45    let (rest, input) = take(size - 4)(input)?;
46    let (input, _) = tag(FRAME_MAGIC_NUMBER.as_slice()).parse(input)?;
47    let (input, chunk_count) = word(input)?;
48    let (input, duration) = word(input)?;
49    let (input, _) = take(2usize)(input)?;
50    let (input, chunk_count) = match parse_dword_as_usize(input)? {
51        (input, 0) => (input, chunk_count.into()),
52        (input, chunk_count) => (input, chunk_count),
53    };
54    let (_, chunks) = parse_chunks(input, chunk_count)?;
55    Ok((rest, RawFrame { duration, chunks }))
56}