libmagic_rs/evaluator/offset/
mod.rs1mod absolute;
10mod indirect;
11mod relative;
12
13pub use absolute::{OffsetError, resolve_absolute_offset};
14
15use crate::LibmagicError;
16use crate::parser::ast::OffsetSpec;
17
18fn map_offset_error(e: &OffsetError, original_offset: i64) -> LibmagicError {
20 match e {
21 OffsetError::BufferOverrun {
22 offset,
23 buffer_len: _,
24 } => LibmagicError::EvaluationError(crate::error::EvaluationError::BufferOverrun {
25 offset: *offset,
26 }),
27 OffsetError::InvalidOffset { reason: _ } | OffsetError::ArithmeticOverflow => {
28 LibmagicError::EvaluationError(crate::error::EvaluationError::InvalidOffset {
29 offset: original_offset,
30 })
31 }
32 }
33}
34
35pub fn resolve_offset(spec: &OffsetSpec, buffer: &[u8]) -> Result<usize, LibmagicError> {
67 match spec {
68 OffsetSpec::Absolute(offset) => {
69 resolve_absolute_offset(*offset, buffer).map_err(|e| map_offset_error(&e, *offset))
70 }
71 OffsetSpec::Indirect { .. } => indirect::resolve_indirect_offset(spec, buffer),
72 OffsetSpec::Relative(_) => relative::resolve_relative_offset(spec, buffer),
73 OffsetSpec::FromEnd(offset) => {
74 resolve_absolute_offset(*offset, buffer).map_err(|e| map_offset_error(&e, *offset))
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_resolve_offset_absolute() {
86 let buffer = b"Test data for offset resolution";
87 let spec = OffsetSpec::Absolute(5);
88
89 let result = resolve_offset(&spec, buffer).unwrap();
90 assert_eq!(result, 5);
91 }
92
93 #[test]
94 fn test_resolve_offset_absolute_negative() {
95 let buffer = b"Test data";
96 let spec = OffsetSpec::Absolute(-4);
97
98 let result = resolve_offset(&spec, buffer).unwrap();
99 assert_eq!(result, 5); }
101
102 #[test]
103 fn test_resolve_offset_from_end() {
104 let buffer = b"Test data";
105 let spec = OffsetSpec::FromEnd(-3);
106
107 let result = resolve_offset(&spec, buffer).unwrap();
108 assert_eq!(result, 6); }
110
111 #[test]
112 fn test_resolve_offset_absolute_out_of_bounds() {
113 let buffer = b"Short";
114 let spec = OffsetSpec::Absolute(10);
115
116 let result = resolve_offset(&spec, buffer);
117 assert!(result.is_err());
118
119 match result.unwrap_err() {
120 LibmagicError::EvaluationError(crate::error::EvaluationError::BufferOverrun {
121 ..
122 }) => {
123 }
125 _ => panic!("Expected EvaluationError with BufferOverrun"),
126 }
127 }
128
129 #[test]
130 fn test_resolve_offset_indirect_not_implemented() {
131 let buffer = b"Test data";
132 let spec = OffsetSpec::Indirect {
133 base_offset: 0,
134 pointer_type: crate::parser::ast::TypeKind::Byte { signed: true },
135 adjustment: 0,
136 endian: crate::parser::ast::Endianness::Little,
137 };
138
139 let result = resolve_offset(&spec, buffer);
140 assert!(result.is_err());
141
142 match result.unwrap_err() {
143 LibmagicError::EvaluationError(crate::error::EvaluationError::UnsupportedType {
144 type_name,
145 }) => {
146 assert!(type_name.contains("Indirect offsets not yet implemented"));
147 }
148 _ => panic!("Expected EvaluationError with UnsupportedType"),
149 }
150 }
151
152 #[test]
153 fn test_resolve_offset_relative_not_implemented() {
154 let buffer = b"Test data";
155 let spec = OffsetSpec::Relative(4);
156
157 let result = resolve_offset(&spec, buffer);
158 assert!(result.is_err());
159
160 match result.unwrap_err() {
161 LibmagicError::EvaluationError(crate::error::EvaluationError::UnsupportedType {
162 type_name,
163 }) => {
164 assert!(type_name.contains("Relative offsets not yet implemented"));
165 }
166 _ => panic!("Expected EvaluationError with UnsupportedType"),
167 }
168 }
169
170 #[test]
171 fn test_resolve_offset_comprehensive() {
172 let buffer = b"0123456789ABCDEF";
173
174 let test_cases = vec![
176 (OffsetSpec::Absolute(0), 0),
177 (OffsetSpec::Absolute(8), 8),
178 (OffsetSpec::Absolute(15), 15),
179 (OffsetSpec::Absolute(-1), 15),
180 (OffsetSpec::Absolute(-8), 8),
181 (OffsetSpec::Absolute(-16), 0),
182 (OffsetSpec::FromEnd(-1), 15),
183 (OffsetSpec::FromEnd(-8), 8),
184 (OffsetSpec::FromEnd(-16), 0),
185 ];
186
187 for (spec, expected) in test_cases {
188 let result = resolve_offset(&spec, buffer).unwrap();
189 assert_eq!(result, expected, "Failed for spec: {spec:?}");
190 }
191 }
192}