1use hayro_jpeg2000::{DecodeSettings, DecoderContext, Image};
25use serde::{Deserialize, Serialize};
26
27use super::{Grib2Error, be_i16, be_u32, malformed, need, unpack};
28
29pub const MAX_BITS: u8 = 21;
32
33pub const MAX_SIDE: u32 = 60_000;
36
37#[non_exhaustive]
39#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
40pub struct Jpeg2000Packing {
41 pub reference: f32,
43 pub binary_scale: i16,
45 pub decimal_scale: i16,
47 pub bits: u8,
51 pub count: u32,
53}
54
55impl Jpeg2000Packing {
56 #[must_use]
58 pub fn unpack(&self, x: u32) -> f64 {
59 unpack(
60 self.reference,
61 self.binary_scale,
62 self.decimal_scale,
63 f64::from(x),
64 )
65 }
66}
67
68pub(super) fn read(s: &[u8], message: usize) -> Result<Jpeg2000Packing, Grib2Error> {
70 let s = need(s, 23, "data template 5.40", message)?;
71 let unsupported = |what, value: u8| Grib2Error::Unsupported {
72 message,
73 what,
74 value: value.into(),
75 };
76 let bits = s[19];
77 if bits > MAX_BITS {
78 return Err(unsupported("bits per value in JPEG 2000", bits));
79 }
80 if s[20] > 1 {
82 return Err(unsupported("type of original field values", s[20]));
83 }
84 if s[21] != 0 {
86 return Err(unsupported("type of JPEG 2000 compression", s[21]));
87 }
88 let reference = f32::from_bits(be_u32(&s[11..15]));
89 if !reference.is_finite() {
90 return Err(malformed(message, "the reference value is not finite"));
91 }
92 Ok(Jpeg2000Packing {
93 reference,
94 binary_scale: be_i16(&s[15..17]),
95 decimal_scale: be_i16(&s[17..19]),
96 bits,
97 count: be_u32(&s[5..9]),
98 })
99}
100
101fn settings() -> DecodeSettings {
102 DecodeSettings {
103 resolve_palette_indices: false,
105 strict: true,
108 ..DecodeSettings::default()
109 }
110}
111
112pub(super) fn check(p: &Jpeg2000Packing, data: &[u8], message: usize) -> Result<(), Grib2Error> {
117 if p.bits == 0 {
118 return Ok(());
119 }
120 let header = Header::read(data, message)?;
121 let samples = u64::from(header.width) * u64::from(header.height);
122 if samples != u64::from(p.count) {
123 return Err(malformed(
124 message,
125 format!(
126 "the JPEG 2000 image has {samples} samples ({} by {}) but section 5 packs {} values",
127 header.width, header.height, p.count
128 ),
129 ));
130 }
131 if header.bits != p.bits {
132 return Err(malformed(
133 message,
134 format!(
135 "the JPEG 2000 image has {} bits per sample but section 5 gives {}",
136 header.bits, p.bits
137 ),
138 ));
139 }
140 Ok(())
141}
142
143enum Coding {
145 Style,
147 Quantization,
149 Other,
151}
152
153struct Header {
155 width: u32,
156 height: u32,
157 bits: u8,
158}
159
160impl Header {
161 fn read(data: &[u8], message: usize) -> Result<Self, Grib2Error> {
164 let bad = |reason: &str| malformed(message, format!("the JPEG 2000 codestream: {reason}"));
165 let unsupported = |what, value: u64| Grib2Error::Unsupported {
166 message,
167 what,
168 value,
169 };
170 let u16_at = |at: usize| -> Result<u16, Grib2Error> {
171 data.get(at..at.saturating_add(2))
172 .map(|b| u16::from_be_bytes([b[0], b[1]]))
173 .ok_or_else(|| bad("its header is cut short"))
174 };
175 let u32_at = |at: usize| -> Result<u32, Grib2Error> {
176 data.get(at..at.saturating_add(4))
177 .map(be_u32)
178 .ok_or_else(|| bad("its header is cut short"))
179 };
180 let byte = |at: usize| -> Result<u8, Grib2Error> {
181 data.get(at)
182 .copied()
183 .ok_or_else(|| bad("its header is cut short"))
184 };
185 if u16_at(0)? != 0xFF4F || u16_at(2)? != 0xFF51 {
186 return Err(bad("it does not start with SOC and SIZ"));
187 }
188 let (x, y) = (u32_at(8)?, u32_at(12)?);
191 if x > MAX_SIDE || y > MAX_SIDE {
192 return Err(unsupported("JPEG 2000 image side", x.max(y).into()));
193 }
194 let (x0, y0) = (u32_at(16)?, u32_at(20)?);
195 let (xt, yt) = (u32_at(24)?, u32_at(28)?);
196 let (xt0, yt0) = (u32_at(32)?, u32_at(36)?);
197 let components = u16_at(40)?;
198 if components != 1 {
199 return Err(unsupported("JPEG 2000 components", components.into()));
200 }
201 let ssiz = byte(42)?;
202 if ssiz & 0x80 != 0 {
203 return Err(unsupported("JPEG 2000 signed samples", ssiz.into()));
204 }
205 let (xr, yr) = (byte(43)?, byte(44)?);
206 if (xr, yr) != (1, 1) {
207 return Err(unsupported(
208 "JPEG 2000 subsampling",
209 u64::from(xr) << 8 | u64::from(yr),
210 ));
211 }
212 if x0 != 0 || y0 != 0 || xt0 != 0 || yt0 != 0 {
213 return Err(unsupported(
214 "JPEG 2000 image or tile offset",
215 u64::from(x0.max(y0).max(xt0).max(yt0)),
216 ));
217 }
218 if xt < x || yt < y {
219 return Err(unsupported(
220 "JPEG 2000 tiles",
221 u64::from(x.div_ceil(xt.max(1))) * u64::from(y.div_ceil(yt.max(1))),
222 ));
223 }
224 let fixed = |at: usize, length: u16| -> Result<(), Grib2Error> {
228 let marker = u16_at(at)?;
229 let have = u16_at(at.saturating_add(2))?;
230 if have == length {
231 Ok(())
232 } else {
233 Err(malformed(
234 message,
235 format!(
236 "the JPEG 2000 codestream: marker {marker:#06X} is {have} bytes long, not {length}"
237 ),
238 ))
239 }
240 };
241 let coding = |marker: u16, at: usize| -> Result<Option<Coding>, Grib2Error> {
244 let precincts = |scod: u8| {
246 if scod & 1 == 0 {
247 Ok(())
248 } else {
249 Err(unsupported("JPEG 2000 precinct sizes", scod.into()))
250 }
251 };
252 let transform = |t: u8| {
253 if t == 1 {
254 Ok(())
255 } else {
256 Err(unsupported("JPEG 2000 wavelet transform", t.into()))
257 }
258 };
259 let quantization = |sq: u8| {
261 if sq & 0x1F == 0 {
262 Ok(())
263 } else {
264 Err(unsupported("JPEG 2000 quantization", (sq & 0x1F).into()))
265 }
266 };
267 Ok(Some(match marker {
268 0xFF52 => {
271 fixed(at, 12)?;
272 precincts(byte(at + 4)?)?;
273 transform(byte(at + 13)?)?;
274 Coding::Style
275 }
276 0xFF53 => {
278 fixed(at, 9)?;
279 precincts(byte(at + 5)?)?;
280 transform(byte(at + 10)?)?;
281 Coding::Other
282 }
283 0xFF5C => {
285 quantization(byte(at + 4)?)?;
286 Coding::Quantization
287 }
288 0xFF5D => {
290 quantization(byte(at + 5)?)?;
291 Coding::Other
292 }
293 0xFF64 => Coding::Other,
295 _ => return Ok(None),
296 }))
297 };
298 fixed(2, 41)?;
301 let mut at = 4 + usize::from(u16_at(4)?);
302 let (mut cod, mut qcd) = (false, false);
303 loop {
304 let marker = u16_at(at)?;
305 if marker == 0xFF90 {
307 break;
308 }
309 let length = usize::from(u16_at(at.saturating_add(2))?);
310 if length < 2 {
311 return Err(bad("a marker segment is shorter than its length field"));
312 }
313 match coding(marker, at)? {
314 Some(Coding::Style) => cod = true,
315 Some(Coding::Quantization) => qcd = true,
316 Some(Coding::Other) => {}
317 None if matches!(marker, 0xFF55 | 0xFF57) => {}
319 None => return Err(unsupported("JPEG 2000 main-header marker", marker.into())),
320 }
321 at = at.saturating_add(2 + length);
322 }
323 if !(cod && qcd) {
324 return Err(bad("its main header has no COD or no QCD"));
325 }
326 while u16_at(at)? == 0xFF90 {
328 fixed(at, 10)?;
329 let psot = usize::try_from(u32_at(at.saturating_add(6))?).unwrap_or(usize::MAX);
330 let mut marker_at = at.saturating_add(2 + usize::from(u16_at(at.saturating_add(2))?));
331 loop {
332 let marker = u16_at(marker_at)?;
333 if marker == 0xFF93 {
334 break;
335 }
336 if coding(marker, marker_at)?.is_none() && marker != 0xFF58 {
338 return Err(unsupported("JPEG 2000 tile-part marker", marker.into()));
339 }
340 let length = usize::from(u16_at(marker_at.saturating_add(2))?);
341 if length < 2 {
342 return Err(bad("a marker segment is shorter than its length field"));
343 }
344 marker_at = marker_at.saturating_add(2 + length);
345 }
346 if psot == 0 {
348 break;
349 }
350 if psot < 14 {
351 return Err(bad("a tile-part is shorter than its header"));
352 }
353 at = at.saturating_add(psot);
354 if at.saturating_add(2) > data.len() || u16_at(at)? == 0xFFD9 {
355 break;
356 }
357 }
358 let bits = (ssiz & 0x7F) + 1;
359 Ok(Self {
360 width: x,
361 height: y,
362 bits,
363 })
364 }
365}
366
367pub(super) fn decode(
369 p: &Jpeg2000Packing,
370 data: &[u8],
371 message: usize,
372) -> Result<Vec<u32>, Grib2Error> {
373 let count = usize::try_from(p.count).unwrap_or(0);
375 if p.bits == 0 {
376 return Ok(vec![0; count]);
377 }
378 if p.bits > MAX_BITS {
380 return Err(Grib2Error::Unsupported {
381 message,
382 what: "bits per value in JPEG 2000",
383 value: p.bits.into(),
384 });
385 }
386 check(p, data, message)?;
387 let codestream = |e| malformed(message, format!("the JPEG 2000 codestream: {e}"));
388 let image = Image::new(data, &settings()).map_err(codestream)?;
389 let mut context = DecoderContext::default();
390 let decoded = image.decode(&mut context).map_err(codestream)?;
391 let [component] = decoded.components() else {
392 return Err(malformed(
393 message,
394 format!(
395 "the JPEG 2000 image has {} components, not one",
396 decoded.components().len()
397 ),
398 ));
399 };
400 let samples = component.samples();
401 if samples.len() != count {
402 return Err(malformed(
403 message,
404 format!(
405 "the JPEG 2000 image decodes to {} samples but section 5 packs {count} values",
406 samples.len()
407 ),
408 ));
409 }
410 let largest = (1_u32 << p.bits) - 1;
411 samples
412 .iter()
413 .map(|&s| {
414 whole(s, largest).ok_or_else(|| {
415 malformed(
416 message,
417 format!("a JPEG 2000 sample, {s}, is not a whole number from 0 to {largest}"),
418 )
419 })
420 })
421 .collect()
422}
423
424#[allow(
428 clippy::cast_possible_truncation,
429 clippy::cast_sign_loss,
430 clippy::cast_precision_loss,
431 reason = "`largest` is below 2^24, so exact in f32, and `s` is checked whole and in range first"
432)]
433fn whole(s: f32, largest: u32) -> Option<u32> {
434 (s.fract() == 0.0 && (0.0..=largest as f32).contains(&s)).then_some(s as u32)
435}