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 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}