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