1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/// An error that occurred while parsing a JPEG file.
#[derive(Clone, Debug, PartialEq, PartialOrd, Hash)]
pub enum JpegConstructionError {
/// The first marker in a JPEG file should be a `SOI`.
///
/// However, this file had another marker first.
FirstMarkerWasNotSoi {
/// The first marker's marker code.
marker_code: u8,
},
/// The first byte of a marker should be `0xFF`.
///
/// It wasn't!
FirstMarkerByteWasWrong(u8),
/// Failed to get a marker code.
///
/// Might be out of data before finding one.
NoMarkerCode,
/// A marker code was `0` or `255`, but those values are disallowed.
MarkerCodeDisallowed(u8),
/// This marker code has a known length, but its length wasn't found.
NoLength {
/// The marker code for which the length was not found.
marker_code: u8,
},
/// A marker had a negative length (after removing 2 len bytes).
NegativeLength {
/// The afflicted marker's marker code.
marker_code: u8,
/// Its original length, including the marker length bytes.
original_len: u16,
},
/// Not enough data for marker payload.
NoDataForPayload {
/// The afflicted marker's marker code.
marker_code: u8,
/// Its original length, including the marker length bytes.
original_len: u16,
/// The remaining length in the input, as of parsing.
///
/// This should be more than `original_len`, but it wasn't!
remaining_input_len: u64,
},
/// Ran outta data when parsing APP1.
OuttaDataForApp1,
/// Ran outta data when parsing SOS.
OuttaDataForSos,
/// No more data for grabbing the ExtendedXMP's offset.
NoOffsetForExtendedXmp,
/// We found multiple StandardXMP blobs.
///
/// We can't use them since we don't know what order they're in.
MultipleStandardXmpBlobs,
/// Attempted to concatenate `ExtendedXMP` blobs, but there wasn't a
/// `StandardXMP` blob to start with!
CantConcatExtendedXmpWithoutStandardXmp,
/// Couldn't find a chunk of `XMP` metadata required for `ExtendedXMP`.
ExtendedXmpMissingChunk {
/// The offset at which the missing chunk was expected to be.
offset: u32,
},
/// We're required to parse the XMP metadata to remove a marker tag before
/// providing things to the user, per the XMP standard.
///
/// However, the XMP failed to parse, meaning this is an invalid JPEG.
XmpDidntParse(crate::XmpError),
/// No GUID was found for the ExtendedXMP, but ExtendedXMP was present.
ExtendedXmpCouldntFindGuid,
/// The detected GUID was not 32 bytes long.
ExtendedXmpGuidNot32Bytes(String),
/// Failed to write modified XMP back to `Vec`.
ExtendedXmpWriteFailure,
}
impl core::fmt::Display for JpegConstructionError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::FirstMarkerWasNotSoi { marker_code } => write!(
f,
"A JPEG file's first marker should be SOI (`0xD8`), \
but it was: `{marker_code:x?}`"
),
Self::FirstMarkerByteWasWrong(other) => write!(
f,
"JPEG marker's first byte was wrong. \
expected: `255`; \
got: `{other}`",
),
Self::NoMarkerCode => f.write_str(
"Failed to get a marker code. \
Might be out of data!",
),
Self::MarkerCodeDisallowed(code) => write!(
f,
"A JPEG marker code had a disallowed value. \
expected: any value that's not `0` or `255`; \
got: `{code}`",
),
Self::NoLength { marker_code } => write!(
f,
"JPEG marker segment with code `{marker_code}` had no length. \
(out of data!) ",
),
Self::NegativeLength {
marker_code,
original_len,
} => write!(
f,
"JPEG marker segment with code `{marker_code}` had \
a length that becomes negative after removing 2: \
`{original_len}` bytes"
),
Self::NoDataForPayload {
marker_code,
original_len: payload_len,
remaining_input_len,
} => write!(
f,
"Not enough data left in input for payload. \
marker code: `{marker_code}`, \
payload len: `{payload_len}` bytes, \
remaining input len: `{remaining_input_len}` bytes"
),
Self::OuttaDataForApp1 => f.write_str(
"Ran out of data when parsing APP1. \
Not enough data for payload.",
),
Self::OuttaDataForSos => f.write_str(
"Ran out of data when parsing SOS. \
Not enough data for payload.",
),
Self::NoOffsetForExtendedXmp => {
f.write_str("No more data for parsing ExtendedXMP's offset.")
}
Self::MultipleStandardXmpBlobs => f.write_str(
"Found multiple StandardXMP blobs, but these \
should be independent.",
),
Self::CantConcatExtendedXmpWithoutStandardXmp => f.write_str(
"Tried to concatenate ExtendedXMP blobs, but no StandardXMP \
blob was found to start with!",
),
Self::ExtendedXmpMissingChunk { offset } => write!(
f,
"Missing an ExtendedXMP blob at byte offset: \
`{offset}`"
),
Self::XmpDidntParse(e) => write!(
f,
"XMP failed to parse. \
Checking this is required when the file contains XMP. err: {e}"
),
Self::ExtendedXmpCouldntFindGuid => f.write_str(
"No GUID was found for the ExtendedXMP, \
but ExtendedXMP was present.",
),
Self::ExtendedXmpGuidNot32Bytes(guid) => write!(
f,
"The found GUID was not 32 bytes long! got: `{guid}`, \
which is `{}` bytes long",
guid.len()
),
Self::ExtendedXmpWriteFailure => f.write_str("Failed to write back to StandardXMP."),
}
}
}
impl core::error::Error for JpegConstructionError {}