1use crate::integrity::{CorruptReason, Truncation};
4use std::fmt;
5
6pub type Result<T, E = Error> = std::result::Result<T, E>;
8
9#[derive(Debug, thiserror::Error)]
14#[non_exhaustive]
15pub enum Error {
16 #[error("unsupported or unrecognised file format{}", fmt_ctx(.0))]
18 UnsupportedFormat(String),
19
20 #[error("unsupported compression in {format}: {compression}")]
22 UnsupportedCompression {
23 format: &'static str,
25 compression: String,
27 },
28
29 #[error("corrupt file: {what}{}", fmt_offset(.offset, .reason))]
34 #[non_exhaustive]
35 CorruptFile {
36 what: String,
38 offset: Option<u64>,
40 reason: Option<Box<CorruptReason>>,
42 },
43
44 #[error("invalid metadata: {0}")]
46 InvalidMetadata(String),
47
48 #[error("unsupported camera: {make} {model}{}", fmt_ctx(.reason))]
50 CameraUnsupported {
51 make: String,
53 model: String,
55 reason: String,
57 },
58
59 #[error("GPU unavailable: {0}")]
61 GpuUnavailable(String),
62
63 #[error("out of memory: {0}")]
65 OutOfMemory(String),
66
67 #[error("limit exceeded: {0}")]
69 LimitExceeded(String),
70
71 #[error("not available: {0}")]
73 NotAvailable(String),
74
75 #[error("invalid argument: {0}")]
77 InvalidArgument(String),
78
79 #[error("I/O error: {0}")]
81 Io(#[from] std::io::Error),
82}
83
84fn fmt_offset(offset: &Option<u64>, reason: &Option<Box<CorruptReason>>) -> String {
85 match (offset, reason) {
86 (Some(o), None) => format!(" (at offset {o:#x})"),
88 _ => String::new(),
89 }
90}
91
92fn fmt_ctx(s: &str) -> String {
93 if s.is_empty() { String::new() } else { format!(": {s}") }
94}
95
96impl Error {
97 #[cold]
99 pub fn corrupt(what: impl fmt::Display) -> Self {
100 Error::CorruptFile { what: what.to_string(), offset: None, reason: None }
101 }
102
103 #[cold]
105 pub fn corrupt_at(what: impl fmt::Display, offset: u64) -> Self {
106 Error::CorruptFile { what: what.to_string(), offset: Some(offset), reason: None }
107 }
108
109 #[cold]
111 pub fn truncated(t: Truncation) -> Self {
112 Error::CorruptFile {
113 what: t.to_string(),
114 offset: Some(t.offset),
115 reason: Some(Box::new(CorruptReason::Truncated(t))),
116 }
117 }
118
119 #[cold]
121 pub fn corrupt_with(reason: CorruptReason) -> Self {
122 let offset = reason.truncation().map(|t| t.offset);
123 Error::CorruptFile { what: reason.to_string(), offset, reason: Some(Box::new(reason)) }
124 }
125
126 pub fn or_truncated(self, file_len: usize, unit: crate::DataUnit, offset: usize, declared: usize) -> Self {
133 match self {
134 Error::CorruptFile { reason: None, .. } => {
135 match crate::integrity::check_range(file_len, unit, offset, declared) {
136 Ok(()) => self,
137 Err(t) => Error::truncated(t),
138 }
139 }
140 e => e,
141 }
142 }
143
144 pub fn corrupt_reason(&self) -> Option<&CorruptReason> {
146 match self {
147 Error::CorruptFile { reason, .. } => reason.as_deref(),
148 _ => None,
149 }
150 }
151
152 pub fn truncation(&self) -> Option<&Truncation> {
154 self.corrupt_reason().and_then(CorruptReason::truncation)
155 }
156
157 #[cold]
159 pub fn invalid_metadata(what: impl fmt::Display) -> Self {
160 Error::InvalidMetadata(what.to_string())
161 }
162
163 #[cold]
165 pub fn unsupported_compression(format: &'static str, compression: impl fmt::Display) -> Self {
166 Error::UnsupportedCompression { format, compression: compression.to_string() }
167 }
168
169 pub fn kind(&self) -> &'static str {
171 match self {
172 Error::UnsupportedFormat(_) => "UnsupportedFormat",
173 Error::UnsupportedCompression { .. } => "UnsupportedCompression",
174 Error::CorruptFile { .. } => "CorruptFile",
175 Error::InvalidMetadata(_) => "InvalidMetadata",
176 Error::CameraUnsupported { .. } => "CameraUnsupported",
177 Error::GpuUnavailable(_) => "GpuUnavailable",
178 Error::OutOfMemory(_) => "OutOfMemory",
179 Error::LimitExceeded(_) => "LimitExceeded",
180 Error::NotAvailable(_) => "NotAvailable",
181 Error::InvalidArgument(_) => "InvalidArgument",
182 Error::Io(_) => "Io",
183 }
184 }
185}
186
187#[macro_export]
189macro_rules! bail_corrupt {
190 ($($arg:tt)*) => { return Err($crate::Error::corrupt(format!($($arg)*))) };
191}
192
193#[macro_export]
195macro_rules! ensure_corrupt {
196 ($cond:expr, $($arg:tt)*) => {
197 if !$cond { return Err($crate::Error::corrupt(format!($($arg)*))); }
198 };
199}