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