aseprite_loader/binary/chunks/
palette.rs

1use std::ops::RangeInclusive;
2
3use bitflags::bitflags;
4use nom::{bytes::complete::take, combinator::cond, multi::count, Parser};
5
6use crate::binary::{
7    errors::{ParseError, ParseResult},
8    palette::PaletteError,
9    scalars::{
10        parse_color, parse_dword_as_u8, parse_dword_as_usize, parse_string, word, Color, Word,
11    },
12};
13
14#[derive(Debug)]
15pub struct PaletteChunk<'a> {
16    pub indices: RangeInclusive<u8>,
17    pub entries: Vec<PaletteEntry<'a>>,
18}
19
20#[derive(Debug)]
21pub struct PaletteEntry<'a> {
22    pub color: Color,
23    pub name: Option<&'a str>,
24}
25
26bitflags! {
27    pub struct PaletteEntryFlags: Word {
28        const HAS_NAME = 0x1;
29    }
30}
31
32pub fn parse_palette_chunk(input: &[u8]) -> ParseResult<'_, PaletteChunk<'_>> {
33    let (input, palette_size) = parse_dword_as_usize(input)?;
34    let (input, first_color_index) = parse_dword_as_u8(
35        input,
36        ParseError::PaletteError(PaletteError::FirstColorIndexOutOfBounds),
37    )?;
38    let (input, last_color_index) = parse_dword_as_u8(
39        input,
40        ParseError::PaletteError(PaletteError::LastColorIndexOutOfBounds),
41    )?;
42    if first_color_index > last_color_index {
43        return Err(nom::Err::Failure(ParseError::PaletteError(
44            PaletteError::FirstColorIndexGreaterThanLastColorIndex,
45        )));
46    }
47    let (input, _) = take(8usize)(input)?;
48    let (input, entries) = count(parse_palette_entry, palette_size).parse(input)?;
49    Ok((
50        input,
51        PaletteChunk {
52            indices: (first_color_index..=last_color_index),
53            entries,
54        },
55    ))
56}
57
58pub fn parse_palette_entry(input: &[u8]) -> ParseResult<'_, PaletteEntry<'_>> {
59    let (input, flags) = word(input)?;
60    let flags = PaletteEntryFlags::from_bits_truncate(flags);
61    let (input, color) = parse_color(input)?;
62    let (input, name) =
63        cond(flags.contains(PaletteEntryFlags::HAS_NAME), parse_string).parse(input)?;
64    Ok((input, PaletteEntry { color, name }))
65}