1 use std::error::Error;
2 use std::fmt;
3 use std::io;
4 use std::string;
5 
6 use crate::decoder::ifd::Value;
7 use crate::tags::{
8     CompressionMethod, PhotometricInterpretation, PlanarConfiguration, SampleFormat, Tag,
9 };
10 use crate::ColorType;
11 use miniz_oxide::inflate::TINFLStatus;
12 
13 /// Tiff error kinds.
14 #[derive(Debug)]
15 pub enum TiffError {
16     /// The Image is not formatted properly.
17     FormatError(TiffFormatError),
18 
19     /// The Decoder does not support features required by the image.
20     UnsupportedError(TiffUnsupportedError),
21 
22     /// An I/O Error occurred while decoding the image.
23     IoError(io::Error),
24 
25     /// The Limits of the Decoder is exceeded.
26     LimitsExceeded,
27 
28     /// An integer conversion to or from a platform size failed, either due to
29     /// limits of the platform size or limits of the format.
30     IntSizeError,
31 }
32 
33 /// The image is not formatted properly.
34 ///
35 /// This indicates that the encoder producing the image might behave incorrectly or that the input
36 /// file has been corrupted.
37 ///
38 /// The list of variants may grow to incorporate errors of future features. Matching against this
39 /// exhaustively is not covered by interface stability guarantees.
40 #[derive(Debug, Clone, PartialEq)]
41 pub enum TiffFormatError {
42     TiffSignatureNotFound,
43     TiffSignatureInvalid,
44     ImageFileDirectoryNotFound,
45     InconsistentSizesEncountered,
46     UnexpectedCompressedData {
47         actual_bytes: usize,
48         required_bytes: usize,
49     },
50     InconsistentStripSamples {
51         actual_samples: usize,
52         required_samples: usize,
53     },
54     InvalidTag,
55     InvalidTagValueType(Tag),
56     RequiredTagNotFound(Tag),
57     UnknownPredictor(u16),
58     ByteExpected(Value),
59     UnsignedIntegerExpected(Value),
60     SignedIntegerExpected(Value),
61     InflateError(InflateError),
62     Format(String),
63     RequiredTagEmpty(Tag),
64     #[doc(hidden)]
65     /// Do not match against this variant. It may get removed.
66     __NonExhaustive,
67 }
68 
69 impl fmt::Display for TiffFormatError {
70     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
71         use self::TiffFormatError::*;
72         match *self {
73             TiffSignatureNotFound => write!(fmt, "TIFF signature not found."),
74             TiffSignatureInvalid => write!(fmt, "TIFF signature invalid."),
75             ImageFileDirectoryNotFound => write!(fmt, "Image file directory not found."),
76             InconsistentSizesEncountered => write!(fmt, "Inconsistent sizes encountered."),
77             UnexpectedCompressedData {
78                 actual_bytes,
79                 required_bytes,
80             } => {
81                 write!(
82                     fmt,
83                     "Decompression returned different amount of bytes than expected: got {}, expected {}.",
84                     actual_bytes, required_bytes
85                 )
86             }
87             InconsistentStripSamples {
88                 actual_samples,
89                 required_samples,
90             } => {
91                 write!(
92                     fmt,
93                     "Inconsistent elements in strip: got {}, expected {}.",
94                     actual_samples, required_samples
95                 )
96             }
97             InvalidTag => write!(fmt, "Image contains invalid tag."),
98             InvalidTagValueType(ref tag) => {
99                 write!(fmt, "Tag `{:?}` did not have the expected value type.", tag)
100             }
101             RequiredTagNotFound(ref tag) => write!(fmt, "Required tag `{:?}` not found.", tag),
102             UnknownPredictor(ref predictor) => {
103                 write!(fmt, "Unknown predictor “{}” encountered", predictor)
104             }
105             ByteExpected(ref val) => write!(fmt, "Expected byte, {:?} found.", val),
106             UnsignedIntegerExpected(ref val) => {
107                 write!(fmt, "Expected unsigned integer, {:?} found.", val)
108             }
109             SignedIntegerExpected(ref val) => {
110                 write!(fmt, "Expected signed integer, {:?} found.", val)
111             }
112             InflateError(_) => write!(fmt, "Failed to decode inflate data."),
113             Format(ref val) => write!(fmt, "Invalid format: {:?}.", val),
114             RequiredTagEmpty(ref val) => write!(fmt, "Required tag {:?} was empty.", val),
115             __NonExhaustive => unreachable!(),
116         }
117     }
118 }
119 
120 /// Decompression failed due to faulty compressed data.
121 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
122 pub struct InflateError {
123     status: TINFLStatus,
124 }
125 
126 impl InflateError {
127     pub(crate) fn new(status: TINFLStatus) -> Self {
128         Self { status }
129     }
130 }
131 
132 impl TiffError {
133     pub(crate) fn from_inflate_status(status: TINFLStatus) -> Self {
134         TiffError::FormatError(TiffFormatError::InflateError(InflateError::new(status)))
135     }
136 }
137 
138 /// The Decoder does not support features required by the image.
139 ///
140 /// This only captures known failures for which the standard either does not require support or an
141 /// implementation has been planned but not yet completed. Some variants may become unused over
142 /// time and will then get deprecated before being removed.
143 ///
144 /// The list of variants may grow. Matching against this exhaustively is not covered by interface
145 /// stability guarantees.
146 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
147 pub enum TiffUnsupportedError {
148     HorizontalPredictor(ColorType),
149     InterpretationWithBits(PhotometricInterpretation, Vec<u8>),
150     UnknownInterpretation,
151     UnknownCompressionMethod,
152     UnsupportedCompressionMethod(CompressionMethod),
153     UnsupportedSampleDepth(u8),
154     UnsupportedSampleFormat(Vec<SampleFormat>),
155     UnsupportedColorType(ColorType),
156     UnsupportedBitsPerChannel(u8),
157     UnsupportedPlanarConfig(Option<PlanarConfiguration>),
158     UnsupportedDataType,
159     #[doc(hidden)]
160     /// Do not match against this variant. It may get removed.
161     __NonExhaustive,
162 }
163 
164 impl fmt::Display for TiffUnsupportedError {
165     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
166         use self::TiffUnsupportedError::*;
167         match *self {
168             HorizontalPredictor(color_type) => write!(
169                 fmt,
170                 "Horizontal predictor for {:?} is unsupported.",
171                 color_type
172             ),
173             InterpretationWithBits(ref photometric_interpretation, ref bits_per_sample) => write!(
174                 fmt,
175                 "{:?} with {:?} bits per sample is unsupported",
176                 photometric_interpretation, bits_per_sample
177             ),
178             UnknownInterpretation => write!(
179                 fmt,
180                 "The image is using an unknown photometric interpretation."
181             ),
182             UnknownCompressionMethod => write!(fmt, "Unknown compression method."),
183             UnsupportedCompressionMethod(method) => {
184                 write!(fmt, "Compression method {:?} is unsupported", method)
185             }
186             UnsupportedSampleDepth(samples) => {
187                 write!(fmt, "{} samples per pixel is unsupported.", samples)
188             }
189             UnsupportedSampleFormat(ref formats) => {
190                 write!(fmt, "Sample format {:?} is unsupported.", formats)
191             }
192             UnsupportedColorType(color_type) => {
193                 write!(fmt, "Color type {:?} is unsupported", color_type)
194             }
195             UnsupportedBitsPerChannel(bits) => {
196                 write!(fmt, "{} bits per channel not supported", bits)
197             }
198             UnsupportedPlanarConfig(config) => {
199                 write!(fmt, "Unsupported planar configuration “{:?}”.", config)
200             }
201             UnsupportedDataType => write!(fmt, "Unsupported data type."),
202             __NonExhaustive => unreachable!(),
203         }
204     }
205 }
206 
207 impl fmt::Display for TiffError {
208     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
209         match *self {
210             TiffError::FormatError(ref e) => write!(fmt, "Format error: {}", e),
211             TiffError::UnsupportedError(ref f) => write!(
212                 fmt,
213                 "The Decoder does not support the \
214                  image format `{}`",
215                 f
216             ),
217             TiffError::IoError(ref e) => e.fmt(fmt),
218             TiffError::LimitsExceeded => write!(fmt, "The Decoder limits are exceeded"),
219             TiffError::IntSizeError => write!(fmt, "Platform or format size limits exceeded"),
220         }
221     }
222 }
223 
224 impl Error for TiffError {
225     fn description(&self) -> &str {
226         match *self {
227             TiffError::FormatError(..) => "Format error",
228             TiffError::UnsupportedError(..) => "Unsupported error",
229             TiffError::IoError(..) => "IO error",
230             TiffError::LimitsExceeded => "Decoder limits exceeded",
231             TiffError::IntSizeError => "Platform or format size limits exceeded",
232         }
233     }
234 
235     fn cause(&self) -> Option<&dyn Error> {
236         match *self {
237             TiffError::IoError(ref e) => Some(e),
238             _ => None,
239         }
240     }
241 }
242 
243 impl From<io::Error> for TiffError {
244     fn from(err: io::Error) -> TiffError {
245         TiffError::IoError(err)
246     }
247 }
248 
249 impl From<string::FromUtf8Error> for TiffError {
250     fn from(_err: string::FromUtf8Error) -> TiffError {
251         TiffError::FormatError(TiffFormatError::InvalidTag)
252     }
253 }
254 
255 impl From<TiffFormatError> for TiffError {
256     fn from(err: TiffFormatError) -> TiffError {
257         TiffError::FormatError(err)
258     }
259 }
260 
261 impl From<TiffUnsupportedError> for TiffError {
262     fn from(err: TiffUnsupportedError) -> TiffError {
263         TiffError::UnsupportedError(err)
264     }
265 }
266 
267 impl From<std::num::TryFromIntError> for TiffError {
268     fn from(_err: std::num::TryFromIntError) -> TiffError {
269         TiffError::IntSizeError
270     }
271 }
272 
273 /// Result of an image decoding/encoding process
274 pub type TiffResult<T> = Result<T, TiffError>;
275