1use crate::types::{DataMemberValue, ExifError};
7use regex::Regex;
8use std::collections::HashMap;
9use std::sync::LazyLock;
10
11static ARRAY_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^(.+)\[(.+)\]$").unwrap());
14static VAL_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\$val\{([^}]+)\}").unwrap());
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum BinaryDataFormat {
20 Int8u,
24 Int8s,
27 Int16u,
30 Int16s,
33 Int32u,
36 Int32s,
39 Float,
42 Double,
45 String,
48 PString,
51 Undef,
54 VarString,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq)]
62pub enum FormatSpec {
63 Fixed(BinaryDataFormat),
65 Array {
68 base_format: BinaryDataFormat,
69 count_expr: String,
70 },
71 StringWithLength { length_expr: String },
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
79pub enum ResolvedFormat {
80 Single(BinaryDataFormat),
82 Array(BinaryDataFormat, usize),
84 StringWithLength(usize),
86 VarString,
88}
89
90impl BinaryDataFormat {
91 pub fn byte_size(self) -> usize {
94 match self {
95 BinaryDataFormat::Int8u | BinaryDataFormat::Int8s | BinaryDataFormat::Undef => 1,
96 BinaryDataFormat::Int16u | BinaryDataFormat::Int16s => 2,
97 BinaryDataFormat::Int32u | BinaryDataFormat::Int32s | BinaryDataFormat::Float => 4,
98 BinaryDataFormat::Double => 8,
99 BinaryDataFormat::String | BinaryDataFormat::PString | BinaryDataFormat::VarString => 1, }
101 }
102
103 pub fn parse_format(format: &str) -> std::result::Result<Self, ExifError> {
106 match format {
107 "int8u" => Ok(BinaryDataFormat::Int8u),
108 "int8s" => Ok(BinaryDataFormat::Int8s),
109 "int16u" => Ok(BinaryDataFormat::Int16u),
110 "int16s" => Ok(BinaryDataFormat::Int16s),
111 "int32u" => Ok(BinaryDataFormat::Int32u),
112 "int32s" => Ok(BinaryDataFormat::Int32s),
113 "float" => Ok(BinaryDataFormat::Float),
114 "double" => Ok(BinaryDataFormat::Double),
115 "string" => Ok(BinaryDataFormat::String),
116 "pstring" => Ok(BinaryDataFormat::PString),
117 "undef" => Ok(BinaryDataFormat::Undef),
118 "var_string" => Ok(BinaryDataFormat::VarString),
119 _ => Err(ExifError::ParseError(format!(
120 "Unknown binary data format: {format}"
121 ))),
122 }
123 }
124}
125
126impl FormatSpec {
127 pub fn parse(format_str: &str) -> std::result::Result<Self, ExifError> {
130 if let Some(captures) = ARRAY_REGEX.captures(format_str) {
132 let base_format_str = captures.get(1).unwrap().as_str();
133 let count_expr = captures.get(2).unwrap().as_str().to_string();
134
135 if base_format_str == "string" {
136 Ok(FormatSpec::StringWithLength {
138 length_expr: count_expr,
139 })
140 } else {
141 let base_format = BinaryDataFormat::parse_format(base_format_str)?;
143 Ok(FormatSpec::Array {
144 base_format,
145 count_expr,
146 })
147 }
148 } else {
149 let format = BinaryDataFormat::parse_format(format_str)?;
151 Ok(FormatSpec::Fixed(format))
152 }
153 }
154
155 pub fn needs_evaluation(&self) -> bool {
157 match self {
158 FormatSpec::Fixed(_) => false,
159 FormatSpec::Array { .. } => true,
160 FormatSpec::StringWithLength { .. } => true,
161 }
162 }
163}
164
165impl ResolvedFormat {
166 pub fn byte_size(&self) -> usize {
168 match self {
169 ResolvedFormat::Single(format) => format.byte_size(),
170 ResolvedFormat::Array(format, count) => format.byte_size() * count,
171 ResolvedFormat::StringWithLength(length) => *length,
172 ResolvedFormat::VarString => 1, }
174 }
175
176 pub fn base_format(&self) -> BinaryDataFormat {
178 match self {
179 ResolvedFormat::Single(format) => *format,
180 ResolvedFormat::Array(format, _) => *format,
181 ResolvedFormat::StringWithLength(_) => BinaryDataFormat::String,
182 ResolvedFormat::VarString => BinaryDataFormat::VarString,
183 }
184 }
185
186 pub fn count(&self) -> usize {
188 match self {
189 ResolvedFormat::Single(_) => 1,
190 ResolvedFormat::Array(_, count) => *count,
191 ResolvedFormat::StringWithLength(_) => 1,
192 ResolvedFormat::VarString => 1,
193 }
194 }
195}
196
197pub struct ExpressionEvaluator<'a> {
200 val_hash: HashMap<u32, DataMemberValue>,
203 data_members: &'a HashMap<String, DataMemberValue>,
206}
207
208impl<'a> ExpressionEvaluator<'a> {
209 pub fn new(
211 val_hash: HashMap<u32, DataMemberValue>,
212 data_members: &'a HashMap<String, DataMemberValue>,
213 ) -> Self {
214 Self {
215 val_hash,
216 data_members,
217 }
218 }
219
220 pub fn evaluate_count_expression(&self, expr: &str) -> std::result::Result<usize, ExifError> {
223 if let Ok(result) = self.evaluate_complex_expression(expr) {
226 return Ok(result);
227 }
228
229 if let Some(captures) = VAL_REGEX.captures(expr) {
231 let val_ref = captures.get(1).unwrap().as_str();
232
233 if let Ok(index) = val_ref.parse::<u32>() {
235 if let Some(value) = self.val_hash.get(&index) {
236 return value.as_usize().ok_or_else(|| {
237 ExifError::ParseError(format!(
238 "Value at index {index} cannot be converted to count"
239 ))
240 });
241 }
242 }
243
244 if let Some(value) = self.data_members.get(val_ref) {
246 return value.as_usize().ok_or_else(|| {
247 ExifError::ParseError(format!(
248 "DataMember '{val_ref}' cannot be converted to count"
249 ))
250 });
251 }
252
253 return Err(ExifError::ParseError(format!(
254 "Unknown value reference: {val_ref}"
255 )));
256 }
257
258 Err(ExifError::ParseError(format!(
260 "Cannot evaluate expression: {expr}"
261 )))
262 }
263
264 pub fn resolve_format(
266 &self,
267 spec: &FormatSpec,
268 ) -> std::result::Result<ResolvedFormat, ExifError> {
269 match spec {
270 FormatSpec::Fixed(format) => Ok(ResolvedFormat::Single(*format)),
271 FormatSpec::Array {
272 base_format,
273 count_expr,
274 } => {
275 let count = self.evaluate_count_expression(count_expr)?;
276 Ok(ResolvedFormat::Array(*base_format, count))
277 }
278 FormatSpec::StringWithLength { length_expr } => {
279 let length = self.evaluate_count_expression(length_expr)?;
280 Ok(ResolvedFormat::StringWithLength(length))
281 }
282 }
283 }
284
285 pub fn evaluate_complex_expression(&self, expr: &str) -> std::result::Result<usize, ExifError> {
289 static CEILING_DIV_REGEX: LazyLock<Regex> =
292 LazyLock::new(|| Regex::new(r"^int\(\(\$val\{(\d+)\}\+(\d+)\)/(\d+)\)$").unwrap());
293
294 if let Some(captures) = CEILING_DIV_REGEX.captures(expr) {
295 let val_index: u32 = captures.get(1).unwrap().as_str().parse().map_err(|_| {
296 ExifError::ParseError("Invalid value index in ceiling division".to_string())
297 })?;
298 let addend: usize = captures.get(2).unwrap().as_str().parse().map_err(|_| {
299 ExifError::ParseError("Invalid addend in ceiling division".to_string())
300 })?;
301 let divisor: usize = captures.get(3).unwrap().as_str().parse().map_err(|_| {
302 ExifError::ParseError("Invalid divisor in ceiling division".to_string())
303 })?;
304
305 if divisor == 0 {
306 return Err(ExifError::ParseError(
307 "Division by zero in expression".to_string(),
308 ));
309 }
310
311 let val = self.val_hash.get(&val_index).ok_or_else(|| {
313 ExifError::ParseError(format!("Value at index {val_index} not found"))
314 })?;
315
316 let val_usize = val.as_usize().ok_or_else(|| {
317 ExifError::ParseError(format!(
318 "Value at index {val_index} cannot be converted to number"
319 ))
320 })?;
321
322 let result = (val_usize + addend) / divisor;
325 return Ok(result);
326 }
327
328 Err(ExifError::ParseError(format!(
330 "Unsupported complex expression: {expr}"
331 )))
332 }
333
334 pub fn set_val(&mut self, index: u32, value: DataMemberValue) {
336 self.val_hash.insert(index, value);
337 }
338}
339
340#[derive(Debug, Clone)]
343pub struct BinaryDataTable {
344 pub default_format: BinaryDataFormat,
346 pub first_entry: Option<u32>,
348 pub groups: HashMap<u8, String>,
350 pub tags: HashMap<u32, BinaryDataTag>,
352 pub data_member_tags: Vec<u32>,
355 pub dependency_order: Vec<u32>,
358}
359
360#[derive(Debug, Clone)]
363pub struct BinaryDataTag {
364 pub name: String,
366 pub format_spec: Option<FormatSpec>,
369 pub format: Option<BinaryDataFormat>,
372 pub mask: Option<u32>,
374 pub print_conv: Option<HashMap<u32, String>>,
376 pub data_member: Option<String>,
379}
380
381impl Default for BinaryDataTable {
382 fn default() -> Self {
383 Self {
384 default_format: BinaryDataFormat::Int8u,
385 first_entry: None,
386 groups: HashMap::new(),
387 tags: HashMap::new(),
388 data_member_tags: Vec::new(),
389 dependency_order: Vec::new(),
390 }
391 }
392}
393
394impl BinaryDataTable {
395 pub fn analyze_dependencies(&mut self) {
398 self.data_member_tags.clear();
400 self.dependency_order.clear();
401
402 for (&index, tag) in &self.tags {
404 if tag.data_member.is_some() {
405 self.data_member_tags.push(index);
406 }
407 }
408
409 self.data_member_tags.sort();
411
412 self.dependency_order.extend(&self.data_member_tags);
414
415 let mut remaining_tags: Vec<u32> = self
417 .tags
418 .keys()
419 .filter(|&index| !self.data_member_tags.contains(index))
420 .copied()
421 .collect();
422
423 remaining_tags.sort();
425 self.dependency_order.extend(remaining_tags);
426 }
427
428 pub fn tag_needs_evaluation(&self, index: u32) -> bool {
430 if let Some(tag) = self.tags.get(&index) {
431 if let Some(format_spec) = &tag.format_spec {
432 return format_spec.needs_evaluation();
433 }
434 }
435 false
436 }
437
438 pub fn get_tag_format_spec(&self, index: u32) -> Option<FormatSpec> {
440 if let Some(tag) = self.tags.get(&index) {
441 if let Some(format_spec) = &tag.format_spec {
442 return Some(format_spec.clone());
443 }
444 if let Some(format) = &tag.format {
445 return Some(FormatSpec::Fixed(*format));
446 }
447 return Some(FormatSpec::Fixed(self.default_format));
449 }
450 None
451 }
452}