aseprite_loader/binary/chunks/
user_data.rs

1use bitflags::bitflags;
2use nom::{
3    bytes::complete::take,
4    combinator::{cond, map},
5    multi::count,
6    number::complete::{
7        le_f32, le_f64, le_i16, le_i32, le_i64, le_i8, le_u16, le_u32, le_u64, le_u8,
8    },
9    Parser,
10};
11use strum::FromRepr;
12
13use crate::binary::{
14    errors::{ParseError, ParseResult},
15    scalars::{
16        byte, dword, fixed, parse_color, parse_dword_as_usize, parse_point, parse_rect, parse_size,
17        parse_string, parse_uuid, word, Color, Double, Dword, Fixed, Float, Point, Rect, Size,
18        Uuid,
19    },
20};
21
22bitflags! {
23    pub struct UserDataFlags: Dword {
24        const HAS_TEXT = 0x1;
25        const HAS_COLOR = 0x2;
26        const HAS_PROPERTIES = 0x4;
27    }
28}
29
30#[derive(Debug)]
31pub struct UserDataChunk<'a> {
32    pub text: Option<&'a str>,
33    pub color: Option<Color>,
34    pub properties_maps: Option<ParseResult<'a, Vec<PropertiesMap<'a>>>>,
35}
36
37#[derive(Debug)]
38pub struct PropertiesMap<'a> {
39    pub properties: Vec<Property<'a>>,
40    pub extension_entry_id: Dword,
41}
42
43#[derive(Debug)]
44pub struct Property<'a> {
45    pub name: &'a str,
46    pub value: Value<'a>,
47}
48
49#[derive(FromRepr, Debug, Copy, Clone)]
50#[repr(u16)]
51pub enum PropertyType {
52    Bool = 0x0001,
53    Int8 = 0x0002,
54    Uint8 = 0x0003,
55    Int16 = 0x0004,
56    Uint16 = 0x0005,
57    Int32 = 0x0006,
58    Uint32 = 0x0007,
59    Int64 = 0x0008,
60    Uint64 = 0x0009,
61    Fixed = 0x000A,
62    Float = 0x000B,
63    Double = 0x000C,
64    String = 0x000D,
65    Point = 0x000E,
66    Size = 0x000F,
67    Rect = 0x0010,
68    Vector = 0x0011,
69    PropertiesMap = 0x0012,
70    Uuid = 0x0013,
71}
72
73#[derive(Debug)]
74pub enum Value<'a> {
75    Bool(bool),
76    Int8(i8),
77    Uint8(u8),
78    Int16(i16),
79    Uint16(u16),
80    Int32(i32),
81    Uint32(u32),
82    Int64(i64),
83    Uint64(u64),
84    Fixed(Fixed),
85    Float(f32),
86    Double(f64),
87    String(&'a str),
88    Point(Point),
89    Size(Size),
90    Rect(Rect),
91    Vector(Vector<'a>),
92    MixedVector(Vec<Value<'a>>),
93    PropertiesMap(PropertiesMap<'a>),
94    Uuid(Uuid),
95}
96
97#[derive(Debug)]
98pub enum Vector<'a> {
99    Mixed(Vec<Value<'a>>),
100    Bool(Vec<bool>),
101    Int8(Vec<i8>),
102    Uint8(Vec<u8>),
103    Int16(Vec<i16>),
104    Uint16(Vec<u16>),
105    Int32(Vec<i32>),
106    Uint32(Vec<u32>),
107    Int64(Vec<i64>),
108    Uint64(Vec<u64>),
109    Fixed(Vec<Fixed>),
110    Float(Vec<Float>),
111    Double(Vec<Double>),
112    String(Vec<&'a str>),
113    Point(Vec<Point>),
114    Size(Vec<Size>),
115    Rect(Vec<Rect>),
116    Vector(Vec<Vector<'a>>),
117    PropertiesMap(Vec<PropertiesMap<'a>>),
118    Uuid(Vec<Uuid>),
119}
120
121pub fn parse_user_data_chunk(input: &[u8]) -> ParseResult<'_, UserDataChunk<'_>> {
122    let (input, flags) = dword(input)?;
123    let flags = UserDataFlags::from_bits_truncate(flags);
124    let (input, text) = cond(flags.contains(UserDataFlags::HAS_TEXT), parse_string).parse(input)?;
125    let (input, color) =
126        cond(flags.contains(UserDataFlags::HAS_COLOR), parse_color).parse(input)?;
127    let (input, properties_maps) = cond(
128        flags.contains(UserDataFlags::HAS_PROPERTIES),
129        parse_properties_maps,
130    )
131    .parse(input)?;
132    Ok((
133        input,
134        (UserDataChunk {
135            text,
136            color,
137            properties_maps,
138        }),
139    ))
140}
141
142pub fn parse_properties_maps(
143    input: &[u8],
144) -> ParseResult<'_, ParseResult<'_, Vec<PropertiesMap<'_>>>> {
145    let (input, size_maps) = parse_dword_as_usize(input)?;
146    let (input, num_maps) = parse_dword_as_usize(input)?;
147    // FIXME handle underflows
148    let (input, input_maps) = take(size_maps - 4)(input)?;
149    Ok((
150        input,
151        count(parse_properties_map, num_maps).parse(input_maps),
152    ))
153}
154
155pub fn parse_properties_map(input: &[u8]) -> ParseResult<'_, PropertiesMap<'_>> {
156    let (input, extension_entry_id) = dword(input)?;
157    let (input, num_props) = parse_dword_as_usize(input)?;
158    let (input, properties) = count(parse_property, num_props).parse(input)?;
159    Ok((
160        input,
161        PropertiesMap {
162            extension_entry_id,
163            properties,
164        },
165    ))
166}
167
168pub fn parse_property(input: &[u8]) -> ParseResult<'_, Property<'_>> {
169    let (input, name) = parse_string(input)?;
170    let (input, value) = parse_value(input)?;
171    Ok((input, Property { name, value }))
172}
173
174pub fn parse_value(input: &[u8]) -> ParseResult<'_, Value<'_>> {
175    let (input, prop_type) = word(input)?;
176    let prop_type = PropertyType::from_repr(prop_type).ok_or(nom::Err::Failure(
177        ParseError::InvalidPropertyType(prop_type),
178    ))?;
179    Ok(match prop_type {
180        PropertyType::Bool => map(byte, |b| Value::Bool(b != 0)).parse(input)?,
181        PropertyType::Int8 => map(le_i8, Value::Int8).parse(input)?,
182        PropertyType::Uint8 => map(le_u8, Value::Uint8).parse(input)?,
183        PropertyType::Int16 => map(le_i16, Value::Int16).parse(input)?,
184        PropertyType::Uint16 => map(le_u16, Value::Uint16).parse(input)?,
185        PropertyType::Int32 => map(le_i32, Value::Int32).parse(input)?,
186        PropertyType::Uint32 => map(le_u32, Value::Uint32).parse(input)?,
187        PropertyType::Int64 => map(le_i64, Value::Int64).parse(input)?,
188        PropertyType::Uint64 => map(le_u64, Value::Uint64).parse(input)?,
189        PropertyType::Fixed => map(fixed, Value::Fixed).parse(input)?,
190        PropertyType::Float => map(le_f32, Value::Float).parse(input)?,
191        PropertyType::Double => map(le_f64, Value::Double).parse(input)?,
192        PropertyType::String => map(parse_string, Value::String).parse(input)?,
193        PropertyType::Point => map(parse_point, Value::Point).parse(input)?,
194        PropertyType::Size => map(parse_size, Value::Size).parse(input)?,
195        PropertyType::Rect => map(parse_rect, Value::Rect).parse(input)?,
196        PropertyType::Vector => map(parse_vector, Value::Vector).parse(input)?,
197        PropertyType::PropertiesMap => {
198            map(parse_properties_map, Value::PropertiesMap).parse(input)?
199        }
200        PropertyType::Uuid => map(parse_uuid, Value::Uuid).parse(input)?,
201    })
202}
203
204pub fn parse_vector(input: &[u8]) -> ParseResult<'_, Vector<'_>> {
205    let (input, len_elements) = parse_dword_as_usize(input)?;
206    let (input, prop_type) = word(input)?;
207    if prop_type == 0 {
208        return map(count(parse_value, len_elements), Vector::Mixed).parse(input);
209    }
210    let prop_type = PropertyType::from_repr(prop_type).ok_or(nom::Err::Failure(
211        ParseError::InvalidPropertyType(prop_type),
212    ))?;
213    let (input, vec) = match prop_type {
214        PropertyType::Bool => {
215            map(count(map(byte, |b| b != 0), len_elements), Vector::Bool).parse(input)?
216        }
217        PropertyType::Int8 => map(count(le_i8, len_elements), Vector::Int8).parse(input)?,
218        PropertyType::Uint8 => map(count(le_u8, len_elements), Vector::Uint8).parse(input)?,
219        PropertyType::Int16 => map(count(le_i16, len_elements), Vector::Int16).parse(input)?,
220        PropertyType::Uint16 => map(count(le_u16, len_elements), Vector::Uint16).parse(input)?,
221        PropertyType::Int32 => map(count(le_i32, len_elements), Vector::Int32).parse(input)?,
222        PropertyType::Uint32 => map(count(le_u32, len_elements), Vector::Uint32).parse(input)?,
223        PropertyType::Int64 => map(count(le_i64, len_elements), Vector::Int64).parse(input)?,
224        PropertyType::Uint64 => map(count(le_u64, len_elements), Vector::Uint64).parse(input)?,
225        PropertyType::Fixed => map(count(fixed, len_elements), Vector::Fixed).parse(input)?,
226        PropertyType::Float => map(count(le_f32, len_elements), Vector::Float).parse(input)?,
227        PropertyType::Double => map(count(le_f64, len_elements), Vector::Double).parse(input)?,
228        PropertyType::String => {
229            map(count(parse_string, len_elements), Vector::String).parse(input)?
230        }
231        PropertyType::Point => map(count(parse_point, len_elements), Vector::Point).parse(input)?,
232        PropertyType::Size => map(count(parse_size, len_elements), Vector::Size).parse(input)?,
233        PropertyType::Rect => map(count(parse_rect, len_elements), Vector::Rect).parse(input)?,
234        PropertyType::Vector => {
235            map(count(parse_vector, len_elements), Vector::Vector).parse(input)?
236        }
237        PropertyType::PropertiesMap => map(
238            count(parse_properties_map, len_elements),
239            Vector::PropertiesMap,
240        )
241        .parse(input)?,
242        PropertyType::Uuid => map(count(parse_uuid, len_elements), Vector::Uuid).parse(input)?,
243    };
244    Ok((input, vec))
245}