exif_oxide/raw/
processor.rs1use crate::exif::ExifReader;
7use crate::file_detection::FileTypeDetectionResult;
8use crate::types::{ExifError, Result};
9use std::collections::HashMap;
10
11use super::{detector::detect_raw_format, RawFormat};
12
13pub trait RawFormatHandler: Send + Sync {
17 fn process_raw(&self, reader: &mut ExifReader, data: &[u8]) -> Result<()>;
20
21 fn name(&self) -> &'static str;
23
24 fn validate_format(&self, data: &[u8]) -> bool;
27}
28
29pub struct RawProcessor {
32 handlers: HashMap<RawFormat, Box<dyn RawFormatHandler>>,
34}
35
36impl RawProcessor {
37 pub fn new() -> Self {
39 let mut handlers: HashMap<RawFormat, Box<dyn RawFormatHandler>> = HashMap::new();
40
41 handlers.insert(
44 RawFormat::Kyocera,
45 Box::new(super::formats::kyocera::KyoceraRawHandler::new()),
46 );
47
48 handlers.insert(
51 RawFormat::Minolta,
52 Box::new(super::formats::minolta::MinoltaRawHandler::new()),
53 );
54
55 handlers.insert(
58 RawFormat::Panasonic,
59 Box::new(super::formats::panasonic::PanasonicRawHandler::new()),
60 );
61
62 Self { handlers }
68 }
69
70 pub fn process_raw(
73 &self,
74 reader: &mut ExifReader,
75 data: &[u8],
76 detection_result: &FileTypeDetectionResult,
77 ) -> Result<()> {
78 let format = detect_raw_format(detection_result);
80
81 if let Some(handler) = self.handlers.get(&format) {
83 if !handler.validate_format(data) {
85 return Err(ExifError::ParseError(format!(
86 "Invalid {} RAW format - failed validation",
87 format.name()
88 )));
89 }
90
91 handler.process_raw(reader, data)?;
93 } else {
94 return Err(ExifError::Unsupported(format!(
95 "Unsupported RAW format: {}",
96 format.name()
97 )));
98 }
99
100 Ok(())
101 }
102
103 pub fn supported_formats(&self) -> Vec<RawFormat> {
105 self.handlers.keys().copied().collect()
106 }
107}
108
109impl Default for RawProcessor {
110 fn default() -> Self {
111 Self::new()
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use crate::types::TagValue;
119
120 #[allow(dead_code)]
122 struct MockRawHandler {
123 name: String,
124 should_validate: bool,
125 }
126
127 impl MockRawHandler {
128 #[allow(dead_code)]
129 fn new(name: String, should_validate: bool) -> Self {
130 Self {
131 name,
132 should_validate,
133 }
134 }
135 }
136
137 impl RawFormatHandler for MockRawHandler {
138 fn process_raw(&self, reader: &mut ExifReader, _data: &[u8]) -> Result<()> {
139 reader.add_test_tag(
141 0x100,
142 TagValue::String("test".to_string()),
143 "TestRAW",
144 "TestIFD",
145 );
146 Ok(())
147 }
148
149 fn name(&self) -> &'static str {
150 "MockHandler"
152 }
153
154 fn validate_format(&self, _data: &[u8]) -> bool {
155 self.should_validate
156 }
157 }
158
159 #[test]
160 fn test_raw_processor_creation() {
161 let processor = RawProcessor::new();
162 let supported = processor.supported_formats();
163
164 assert!(supported.contains(&RawFormat::Kyocera));
165 assert!(supported.contains(&RawFormat::Minolta));
166 assert!(supported.contains(&RawFormat::Panasonic));
167 assert_eq!(supported.len(), 3); }
169
170 #[test]
171 fn test_raw_processor_unsupported_format() {
172 let processor = RawProcessor::new();
173 let mut reader = ExifReader::new();
174
175 let detection_result = FileTypeDetectionResult {
176 file_type: "UNKNOWN".to_string(),
177 format: "UNKNOWN".to_string(),
178 mime_type: "application/octet-stream".to_string(),
179 description: "Unknown format".to_string(),
180 };
181
182 let data = vec![0u8; 100];
183 let result = processor.process_raw(&mut reader, &data, &detection_result);
184
185 assert!(result.is_err());
186 assert!(result
187 .unwrap_err()
188 .to_string()
189 .contains("Unsupported RAW format"));
190 }
191}