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
use nom::{bytes::complete::take, multi::count};

use super::{
    chunk_type::{parse_chunk_type, ChunkType},
    chunks::{
        cel::{parse_cel_chunk, CelChunk},
        cel_extra::{parse_cel_extra_chunk, CelExtraChunk},
        color_profile::{parse_color_profile, ColorProfileChunk},
        external_files::{parse_external_files_chunk, ExternalFilesChunk},
        layer::{parse_layer_chunk, LayerChunk},
        mask::{parse_mask_chunk, MaskChunk},
        old_palette::{parse_old_palette_chunk, OldPaletteChunk},
        palette::{parse_palette_chunk, PaletteChunk},
        slice::{parse_slice_chunk, SliceChunk},
        tags::{parse_tags_chunk, TagsChunk},
        tileset::{parse_tileset_chunk, TilesetChunk},
        user_data::{parse_user_data_chunk, UserDataChunk},
    },
    errors::{ParseError, ParseResult},
    scalars::dword_size,
};

#[derive(Debug)]
pub enum Chunk<'a> {
    Palette0004(OldPaletteChunk),
    Palette0011(OldPaletteChunk),
    Layer(LayerChunk<'a>),
    Cel(CelChunk<'a>),
    CelExtra(CelExtraChunk<'a>),
    ColorProfile(ColorProfileChunk<'a>),
    ExternalFiles(ExternalFilesChunk<'a>),
    Mask(MaskChunk<'a>),
    Path,
    Tags(TagsChunk<'a>),
    Palette(PaletteChunk<'a>),
    UserData(UserDataChunk<'a>),
    Slice(SliceChunk<'a>),
    Tileset(TilesetChunk<'a>),
    Unsupported(u16),
}

pub fn parse_chunks(input: &[u8], chunk_count: usize) -> ParseResult<'_, Vec<Chunk<'_>>> {
    count(parse_chunk, chunk_count)(input)
}

pub fn parse_chunk(input: &[u8]) -> ParseResult<'_, Chunk<'_>> {
    let (input, size) = dword_size(input, ParseError::InvalidFrameSize)?;
    // FIXME handle underflows
    let (rest, input) = take(size - 4)(input)?;
    let (chunk_data, chunk_type) = parse_chunk_type(input)?;
    let chunk = match chunk_type {
        Ok(ChunkType::Palette0004) => Chunk::Palette0004(parse_old_palette_chunk(chunk_data)?.1),
        Ok(ChunkType::Palette0011) => Chunk::Palette0011(parse_old_palette_chunk(chunk_data)?.1),
        Ok(ChunkType::Layer) => Chunk::Layer(parse_layer_chunk(chunk_data)?.1),
        Ok(ChunkType::Cel) => Chunk::Cel(parse_cel_chunk(chunk_data)?.1),
        Ok(ChunkType::CelExtra) => Chunk::CelExtra(parse_cel_extra_chunk(chunk_data)?.1),
        Ok(ChunkType::ColorProfile) => Chunk::ColorProfile(parse_color_profile(chunk_data)?.1),
        Ok(ChunkType::ExternalFile) => {
            Chunk::ExternalFiles(parse_external_files_chunk(chunk_data)?.1)
        }
        Ok(ChunkType::Mask) => Chunk::Mask(parse_mask_chunk(chunk_data)?.1),
        Ok(ChunkType::Path) => Chunk::Path,
        Ok(ChunkType::Tags) => Chunk::Tags(parse_tags_chunk(chunk_data)?.1),
        Ok(ChunkType::Palette) => Chunk::Palette(parse_palette_chunk(chunk_data)?.1),
        Ok(ChunkType::UserData) => Chunk::UserData(parse_user_data_chunk(chunk_data)?.1),
        Ok(ChunkType::Slice) => Chunk::Slice(parse_slice_chunk(chunk_data)?.1),
        Ok(ChunkType::Tileset) => Chunk::Tileset(parse_tileset_chunk(chunk_data)?.1),
        Err(chunk_type) => Chunk::Unsupported(chunk_type),
    };
    Ok((rest, chunk))
}