exif_oxide/processor_registry/processors/
nikon.rs1use super::super::{
12 BinaryDataProcessor, ProcessorCapability, ProcessorContext, ProcessorMetadata, ProcessorResult,
13};
14use crate::implementations::nikon;
15use crate::types::{Result, TagValue};
16use std::collections::HashMap;
17use tracing::debug;
18
19pub struct NikonEncryptedDataProcessor;
28
29impl BinaryDataProcessor for NikonEncryptedDataProcessor {
30 fn can_process(&self, context: &ProcessorContext) -> ProcessorCapability {
31 if !context.is_manufacturer("NIKON CORPORATION") && !context.is_manufacturer("NIKON") {
33 return ProcessorCapability::Incompatible;
34 }
35
36 if context.table_name.starts_with("Nikon::")
38 && (context.table_name.contains("Encrypted") || context.table_name.contains("LensData"))
39 {
40 return ProcessorCapability::Perfect;
41 }
42
43 if context.table_name.starts_with("Nikon::")
45 && context.get_nikon_encryption_keys().is_some()
46 {
47 return ProcessorCapability::Good; }
49
50 ProcessorCapability::Incompatible
52 }
53
54 fn process_data(&self, data: &[u8], context: &ProcessorContext) -> Result<ProcessorResult> {
55 debug!(
56 "Processing Nikon encrypted data with {} bytes for table: {}",
57 data.len(),
58 context.table_name
59 );
60
61 let mut result = ProcessorResult::new();
62
63 let keys = context.get_nikon_encryption_keys();
65
66 if data.len() >= 4 {
68 let has_encryption_signature = detect_nikon_encryption_signature(data);
71
72 if has_encryption_signature {
73 result.add_tag(
74 "EncryptionDetected".to_string(),
75 "Nikon encryption detected".into(),
76 );
77
78 if let Some(encryption_keys) = keys {
80 let (ref serial, count) = encryption_keys;
81 if !serial.is_empty() && count > 0 {
82 let status = format!(
84 "Encrypted data with keys available (serial: {serial}, count: {count})"
85 );
86 result.add_tag("EncryptionStatus".to_string(), TagValue::String(status));
87
88 let mut nikon_keys = nikon::encryption::NikonEncryptionKeys::new(
92 context.manufacturer.clone().unwrap_or_default(),
93 );
94 nikon_keys.store_serial_key(serial.clone());
95 nikon_keys.store_count_key(count);
96 process_encrypted_data_with_existing_impl(
97 data,
98 context,
99 &nikon_keys,
100 &mut result,
101 )?;
102 } else {
103 result.add_tag(
104 "EncryptionStatus".to_string(),
105 TagValue::String(
106 "Encrypted data detected - encryption keys incomplete".to_string(),
107 ),
108 );
109 result.add_warning(
110 "Nikon encryption keys not available for decryption".to_string(),
111 );
112 }
113 } else {
114 result.add_tag(
115 "EncryptionStatus".to_string(),
116 TagValue::String(
117 "Encrypted data detected - no encryption context".to_string(),
118 ),
119 );
120 result.add_warning("No Nikon encryption context available".to_string());
121 }
122 } else {
123 result.add_tag(
125 "EncryptionStatus".to_string(),
126 "No encryption detected".into(),
127 );
128
129 process_unencrypted_nikon_data(data, context, &mut result)?;
131 }
132 } else {
133 result.add_warning("Nikon data too short for encryption detection".to_string());
134 }
135
136 debug!(
137 "Nikon encrypted data processor extracted {} tags with {} warnings",
138 result.extracted_tags.len(),
139 result.warnings.len()
140 );
141
142 Ok(result)
143 }
144
145 fn get_metadata(&self) -> ProcessorMetadata {
146 ProcessorMetadata::new(
147 "Nikon Encrypted Data Processor".to_string(),
148 "Detects and processes Nikon encrypted maker note data".to_string(),
149 )
150 .with_manufacturer("NIKON CORPORATION".to_string())
151 .with_manufacturer("NIKON".to_string())
152 .with_required_context("manufacturer".to_string())
153 .with_optional_context("nikon_encryption_keys".to_string())
154 .with_example_condition("manufacturer.contains('NIKON') && encryption_detected".to_string())
155 }
156}
157
158pub struct NikonAFInfoProcessor;
167
168impl BinaryDataProcessor for NikonAFInfoProcessor {
169 fn can_process(&self, context: &ProcessorContext) -> ProcessorCapability {
170 if !context.is_manufacturer("NIKON CORPORATION") && !context.is_manufacturer("NIKON") {
173 return ProcessorCapability::Incompatible;
174 }
175
176 if context.table_name.starts_with("Nikon::")
178 && (context.table_name.contains("AFInfo") || context.table_name.contains("AF"))
179 && !context.table_name.contains("Encrypted")
180 {
181 return ProcessorCapability::Perfect;
182 }
183
184 if context.table_name.starts_with("Nikon::") && !context.table_name.contains("Encrypted") {
186 return ProcessorCapability::Good;
187 }
188
189 ProcessorCapability::Incompatible
191 }
192
193 fn process_data(&self, data: &[u8], context: &ProcessorContext) -> Result<ProcessorResult> {
194 debug!(
195 "Processing Nikon AF data with {} bytes for table: {}",
196 data.len(),
197 context.table_name
198 );
199
200 let mut result = ProcessorResult::new();
201
202 let mut af_data = HashMap::new();
206 if data.len() >= 2 {
207 let value = context
208 .byte_order
209 .unwrap_or(crate::tiff_types::ByteOrder::LittleEndian)
210 .read_u16(data, 0)?;
211 af_data.insert("AFValue".to_string(), crate::types::TagValue::U16(value));
212 }
213
214 for (tag_name, tag_value) in af_data {
215 result.add_tag(tag_name, tag_value);
216 }
217
218 if let Some(model) = &context.model {
220 result.add_tag(
221 "ProcessedModel".to_string(),
222 TagValue::String(model.clone()),
223 );
224 }
225
226 if result.extracted_tags.is_empty() {
227 result.add_warning("No Nikon AF data extracted".to_string());
228 } else {
229 debug!(
230 "Nikon AF processor extracted {} tags",
231 result.extracted_tags.len()
232 );
233 }
234
235 Ok(result)
236 }
237
238 fn get_metadata(&self) -> ProcessorMetadata {
239 ProcessorMetadata::new(
240 "Nikon AF Info Processor".to_string(),
241 "Processes Nikon autofocus information and AF point data".to_string(),
242 )
243 .with_manufacturer("NIKON CORPORATION".to_string())
244 .with_manufacturer("NIKON".to_string())
245 .with_required_context("manufacturer".to_string())
246 .with_optional_context("model".to_string())
247 .with_example_condition(
248 "manufacturer.contains('NIKON') && table.contains('AF')".to_string(),
249 )
250 }
251}
252
253pub struct NikonLensDataProcessor;
262
263impl BinaryDataProcessor for NikonLensDataProcessor {
264 fn can_process(&self, context: &ProcessorContext) -> ProcessorCapability {
265 if !context.is_manufacturer("NIKON CORPORATION") && !context.is_manufacturer("NIKON") {
267 return ProcessorCapability::Incompatible;
268 }
269
270 if context.table_name.starts_with("Nikon::")
272 && (context.table_name.contains("LensData") || context.table_name.contains("Lens"))
273 {
274 return ProcessorCapability::Perfect;
275 }
276
277 ProcessorCapability::Incompatible
278 }
279
280 fn process_data(&self, data: &[u8], context: &ProcessorContext) -> Result<ProcessorResult> {
281 debug!(
282 "Processing Nikon lens data with {} bytes for table: {}",
283 data.len(),
284 context.table_name
285 );
286
287 let mut result = ProcessorResult::new();
288
289 if detect_nikon_encryption_signature(data) {
291 result.add_warning(
292 "Nikon lens data is encrypted - decryption not implemented".to_string(),
293 );
294 result.add_tag(
295 "LensDataStatus".to_string(),
296 "Encrypted lens data detected".into(),
297 );
298 } else {
299 let mut lens_info = HashMap::new();
303 if data.len() >= 4 {
304 let lens_id = context
305 .byte_order
306 .unwrap_or(crate::tiff_types::ByteOrder::LittleEndian)
307 .read_u32(data, 0)?;
308 lens_info.insert("LensID".to_string(), crate::types::TagValue::U32(lens_id));
309 }
310
311 for (tag_name, tag_value) in lens_info {
312 result.add_tag(tag_name, tag_value);
313 }
314
315 result.add_tag(
316 "LensDataStatus".to_string(),
317 "Unencrypted lens data processed".into(),
318 );
319 }
320
321 debug!(
322 "Nikon lens data processor extracted {} tags",
323 result.extracted_tags.len()
324 );
325
326 Ok(result)
327 }
328
329 fn get_metadata(&self) -> ProcessorMetadata {
330 ProcessorMetadata::new(
331 "Nikon Lens Data Processor".to_string(),
332 "Processes Nikon lens information and database lookup".to_string(),
333 )
334 .with_manufacturer("NIKON CORPORATION".to_string())
335 .with_manufacturer("NIKON".to_string())
336 .with_required_context("manufacturer".to_string())
337 .with_example_condition(
338 "manufacturer.contains('NIKON') && table.contains('Lens')".to_string(),
339 )
340 }
341}
342
343fn detect_nikon_encryption_signature(data: &[u8]) -> bool {
352 if data.len() < 4 {
353 return false;
354 }
355
356 match &data[0..4] {
359 [0x02, 0x00, 0x00, 0x00] => true, [0x02, 0x04, _, _] => true, [0x04, 0x02, _, _] => true, _ => false,
363 }
364}
365
366fn process_encrypted_data_with_existing_impl(
371 _data: &[u8],
372 context: &ProcessorContext,
373 keys: &nikon::encryption::NikonEncryptionKeys,
374 result: &mut ProcessorResult,
375) -> Result<()> {
376 debug!("Processing encrypted Nikon data with existing implementation");
380
381 let manufacturer = context.manufacturer.as_deref().unwrap_or("Unknown");
383 if let Err(e) = nikon::encryption::validate_encryption_keys(keys, manufacturer) {
384 result.add_warning(format!("Encryption key validation failed: {e}"));
385 return Ok(());
386 }
387
388 result.add_tag(
390 "EncryptionKeys".to_string(),
391 TagValue::string(format!(
392 "Serial: {}, Count: {}",
393 keys.get_serial_key().unwrap_or("none"),
394 keys.get_count_key()
395 .map(|c| c.to_string())
396 .unwrap_or("none".to_string())
397 )),
398 );
399
400 Ok(())
404}
405
406fn process_unencrypted_nikon_data(
411 data: &[u8],
412 context: &ProcessorContext,
413 result: &mut ProcessorResult,
414) -> Result<()> {
415 debug!("Processing unencrypted Nikon data");
416
417 let byte_order = context
421 .byte_order
422 .unwrap_or(crate::tiff_types::ByteOrder::LittleEndian);
423
424 if data.len() >= 2 {
425 let value = byte_order.read_u16(data, 0)?;
427 result.add_tag("FirstValue".to_string(), TagValue::U16(value));
428 }
429
430 if data.len() >= 4 {
431 let value = byte_order.read_u32(data, 0)?;
432 result.add_tag("FirstU32Value".to_string(), TagValue::U32(value));
433 }
434
435 result.add_tag("DataLength".to_string(), TagValue::U32(data.len() as u32));
436
437 Ok(())
438}
439
440#[cfg(test)]
441mod tests {
442 use super::*;
443 use crate::formats::FileFormat;
444 use crate::processor_registry::ProcessorContext;
445
446 #[test]
447 fn test_nikon_encrypted_processor_capability() {
448 let processor = NikonEncryptedDataProcessor;
449
450 let context = ProcessorContext::new(FileFormat::Jpeg, "Nikon::Encrypted".to_string())
452 .with_manufacturer("NIKON CORPORATION".to_string());
453
454 assert_eq!(
455 processor.can_process(&context),
456 ProcessorCapability::Perfect
457 );
458
459 let context = ProcessorContext::new(FileFormat::Jpeg, "Nikon::Encrypted".to_string())
461 .with_manufacturer("Canon".to_string());
462
463 assert_eq!(
464 processor.can_process(&context),
465 ProcessorCapability::Incompatible
466 );
467 }
468
469 #[test]
470 fn test_nikon_af_processor_capability() {
471 let processor = NikonAFInfoProcessor;
472
473 let context = ProcessorContext::new(FileFormat::Jpeg, "Nikon::AFInfo".to_string())
475 .with_manufacturer("NIKON CORPORATION".to_string());
476
477 assert_eq!(
478 processor.can_process(&context),
479 ProcessorCapability::Perfect
480 );
481
482 let context = ProcessorContext::new(FileFormat::Jpeg, "Nikon::Main".to_string())
484 .with_manufacturer("NIKON".to_string());
485
486 assert_eq!(processor.can_process(&context), ProcessorCapability::Good);
487 }
488
489 #[test]
490 fn test_nikon_lens_processor_capability() {
491 let processor = NikonLensDataProcessor;
492
493 let context = ProcessorContext::new(FileFormat::Jpeg, "Nikon::LensData".to_string())
495 .with_manufacturer("NIKON CORPORATION".to_string());
496
497 assert_eq!(
498 processor.can_process(&context),
499 ProcessorCapability::Perfect
500 );
501
502 let context = ProcessorContext::new(FileFormat::Jpeg, "Nikon::Other".to_string())
504 .with_manufacturer("NIKON CORPORATION".to_string());
505
506 assert_eq!(
507 processor.can_process(&context),
508 ProcessorCapability::Incompatible
509 );
510 }
511
512 #[test]
513 fn test_encryption_signature_detection() {
514 let encrypted_data = vec![0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04];
516 assert!(detect_nikon_encryption_signature(&encrypted_data));
517
518 let normal_data = vec![0x01, 0x02, 0x03, 0x04];
520 assert!(!detect_nikon_encryption_signature(&normal_data));
521
522 let short_data = vec![0x01, 0x02];
524 assert!(!detect_nikon_encryption_signature(&short_data));
525 }
526
527 #[test]
528 fn test_processor_metadata() {
529 let processor = NikonEncryptedDataProcessor;
530 let metadata = processor.get_metadata();
531
532 assert_eq!(metadata.name, "Nikon Encrypted Data Processor");
533 assert!(metadata
534 .supported_manufacturers
535 .contains(&"NIKON CORPORATION".to_string()));
536 assert!(metadata
537 .supported_manufacturers
538 .contains(&"NIKON".to_string()));
539 assert!(metadata
540 .required_context
541 .contains(&"manufacturer".to_string()));
542 }
543}