1use crate::error::{Error, Result};
4use grib_core::bit::{read_bit, BitReader};
5pub use grib_core::data::{
6 ComplexPackingParams, DataRepresentation, ImagePackingParams, Jpeg2000PackingParams,
7 PngPackingParams, SimplePackingParams, SpatialDifferencingParams,
8};
9
10pub trait DecodeSample: Copy + Sized {
12 fn from_f64(value: f64) -> Self;
13 fn nan() -> Self;
14}
15
16impl DecodeSample for f32 {
17 fn from_f64(value: f64) -> Self {
18 value as f32
19 }
20
21 fn nan() -> Self {
22 f32::NAN
23 }
24}
25
26impl DecodeSample for f64 {
27 fn from_f64(value: f64) -> Self {
28 value
29 }
30
31 fn nan() -> Self {
32 f64::NAN
33 }
34}
35
36pub fn decode_field(
38 data_section: &[u8],
39 representation: &DataRepresentation,
40 bitmap_section: Option<&[u8]>,
41 num_grid_points: usize,
42) -> Result<Vec<f64>> {
43 if data_section.len() < 5 || data_section[4] != 7 {
44 return Err(Error::InvalidSection {
45 section: data_section.get(4).copied().unwrap_or(7),
46 reason: "not a data section".into(),
47 });
48 }
49
50 decode_payload(
51 &data_section[5..],
52 representation,
53 bitmap_section,
54 num_grid_points,
55 )
56}
57
58pub fn decode_field_into<T: DecodeSample>(
61 data_section: &[u8],
62 representation: &DataRepresentation,
63 bitmap_section: Option<&[u8]>,
64 num_grid_points: usize,
65 out: &mut [T],
66) -> Result<()> {
67 if data_section.len() < 5 || data_section[4] != 7 {
68 return Err(Error::InvalidSection {
69 section: data_section.get(4).copied().unwrap_or(7),
70 reason: "not a data section".into(),
71 });
72 }
73
74 decode_payload_into(
75 &data_section[5..],
76 representation,
77 bitmap_section,
78 num_grid_points,
79 out,
80 )
81}
82
83pub(crate) fn decode_payload(
84 payload: &[u8],
85 representation: &DataRepresentation,
86 bitmap_section: Option<&[u8]>,
87 num_grid_points: usize,
88) -> Result<Vec<f64>> {
89 let mut values = vec![0.0; num_grid_points];
90 decode_payload_into(
91 payload,
92 representation,
93 bitmap_section,
94 num_grid_points,
95 &mut values,
96 )?;
97 Ok(values)
98}
99
100pub(crate) fn decode_payload_into<T: DecodeSample>(
101 payload: &[u8],
102 representation: &DataRepresentation,
103 bitmap_section: Option<&[u8]>,
104 num_grid_points: usize,
105 out: &mut [T],
106) -> Result<()> {
107 if out.len() != num_grid_points {
108 return Err(Error::DataLengthMismatch {
109 expected: num_grid_points,
110 actual: out.len(),
111 });
112 }
113
114 let expected_values = match representation {
115 DataRepresentation::SimplePacking(params) => params.encoded_values,
116 DataRepresentation::ComplexPacking(params) => params.encoded_values,
117 DataRepresentation::Jpeg2000Packing(params) => params.packing.encoded_values,
118 DataRepresentation::PngPacking(params) => params.packing.encoded_values,
119 DataRepresentation::Unsupported(template) => {
120 return Err(Error::UnsupportedDataTemplate(*template));
121 }
122 };
123 match bitmap_section {
124 Some(bitmap_payload) => {
125 let present_values = count_bitmap_present_points(bitmap_payload, num_grid_points)?;
126 if expected_values != present_values {
127 return Err(Error::DataLengthMismatch {
128 expected: present_values,
129 actual: expected_values,
130 });
131 }
132 }
133 None if expected_values != num_grid_points => {
134 return Err(Error::DataLengthMismatch {
135 expected: num_grid_points,
136 actual: expected_values,
137 });
138 }
139 None => {}
140 }
141
142 let mut output = OutputCursor::new(out, bitmap_section);
143 match representation {
144 DataRepresentation::SimplePacking(params) => {
145 unpack_simple_into(payload, params, expected_values, &mut output)?
146 }
147 DataRepresentation::ComplexPacking(params) => {
148 unpack_complex_into(payload, params, &mut output)?
149 }
150 DataRepresentation::Jpeg2000Packing(params) => {
151 unpack_jpeg2000_into(payload, params, expected_values, &mut output)?
152 }
153 DataRepresentation::PngPacking(params) => {
154 unpack_png_into(payload, params, expected_values, &mut output)?
155 }
156 DataRepresentation::Unsupported(_) => unreachable!(),
157 }
158 output.finish()
159}
160
161pub fn bitmap_payload(section_bytes: &[u8]) -> Result<Option<&[u8]>> {
163 if section_bytes.len() < 6 {
164 return Err(Error::InvalidSection {
165 section: 6,
166 reason: format!("expected at least 6 bytes, got {}", section_bytes.len()),
167 });
168 }
169 if section_bytes[4] != 6 {
170 return Err(Error::InvalidSection {
171 section: section_bytes[4],
172 reason: "not a bitmap section".into(),
173 });
174 }
175
176 match section_bytes[5] {
177 255 => Ok(None),
178 0 => Ok(Some(§ion_bytes[6..])),
179 indicator => Err(Error::UnsupportedBitmapIndicator(indicator)),
180 }
181}
182
183pub(crate) fn count_bitmap_present_points(
184 bitmap_payload: &[u8],
185 num_grid_points: usize,
186) -> Result<usize> {
187 let full_bytes = num_grid_points / 8;
188 let remaining_bits = num_grid_points % 8;
189 let required_bytes = full_bytes + usize::from(remaining_bits > 0);
190 if bitmap_payload.len() < required_bytes {
191 return Err(Error::DataLengthMismatch {
192 expected: required_bytes,
193 actual: bitmap_payload.len(),
194 });
195 }
196
197 let mut present = bitmap_payload[..full_bytes]
198 .iter()
199 .map(|byte| byte.count_ones() as usize)
200 .sum();
201 if remaining_bits > 0 {
202 let mask = u8::MAX << (8 - remaining_bits);
203 present += (bitmap_payload[full_bytes] & mask).count_ones() as usize;
204 }
205
206 Ok(present)
207}
208
209pub fn unpack_simple(
211 data_bytes: &[u8],
212 params: &SimplePackingParams,
213 num_values: usize,
214) -> Result<Vec<f64>> {
215 let mut values = vec![0.0; num_values];
216 let mut output = OutputCursor::new(&mut values, None);
217 unpack_simple_into(data_bytes, params, num_values, &mut output)?;
218 output.finish()?;
219 Ok(values)
220}
221
222fn unpack_simple_into<T: DecodeSample>(
223 data_bytes: &[u8],
224 params: &SimplePackingParams,
225 num_values: usize,
226 output: &mut OutputCursor<'_, T>,
227) -> Result<()> {
228 let bits = params.bits_per_value as usize;
229 let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
230 let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
231 let reference = params.reference_value as f64;
232 if bits == 0 {
233 let constant = T::from_f64(scale_decoded_value(
234 reference,
235 0.0,
236 binary_factor,
237 decimal_factor,
238 ));
239 for _ in 0..num_values {
240 output.push_present(constant)?;
241 }
242 return Ok(());
243 }
244 if bits > u64::BITS as usize {
245 return Err(Error::UnsupportedPackingWidth(params.bits_per_value));
246 }
247
248 let required_bits = bits
249 .checked_mul(num_values)
250 .ok_or_else(|| Error::Other("bit count overflow during unpacking".into()))?;
251 let required_bytes = required_bits.div_ceil(8);
252 if data_bytes.len() < required_bytes {
253 return Err(Error::Truncated {
254 offset: data_bytes.len() as u64,
255 });
256 }
257
258 let mut reader = BitReader::new(data_bytes);
259
260 for _ in 0..num_values {
261 let packed = reader.read(bits)?;
262 output.push_present(T::from_f64(scale_decoded_value(
263 reference,
264 packed as f64,
265 binary_factor,
266 decimal_factor,
267 )))?;
268 }
269
270 Ok(())
271}
272
273#[cfg(feature = "jpeg2000")]
274fn unpack_jpeg2000_into<T: DecodeSample>(
275 data_bytes: &[u8],
276 params: &Jpeg2000PackingParams,
277 num_values: usize,
278 output: &mut OutputCursor<'_, T>,
279) -> Result<()> {
280 validate_jpeg2000_bits(params.packing.bits_per_value)?;
281
282 let image = jpeg2k::Image::from_bytes(data_bytes)
283 .map_err(|err| Error::Other(format!("JPEG 2000 decode failed: {err}")))?;
284 if image.num_components() != 1 {
285 return Err(Error::Other(format!(
286 "JPEG 2000 GRIB packing requires one component, got {}",
287 image.num_components()
288 )));
289 }
290
291 let component = image
292 .components()
293 .first()
294 .ok_or_else(|| Error::Other("JPEG 2000 image has no components".into()))?;
295 if component.is_signed() {
296 return Err(Error::Other(
297 "JPEG 2000 GRIB packing requires unsigned component data".into(),
298 ));
299 }
300 if component.precision() > u32::from(params.packing.bits_per_value) {
301 return Err(Error::Other(format!(
302 "JPEG 2000 component precision {} exceeds GRIB bits-per-value {}",
303 component.precision(),
304 params.packing.bits_per_value
305 )));
306 }
307
308 let sample_count = image_sample_count(component.width(), component.height())?;
309 if sample_count != num_values {
310 return Err(Error::DataLengthMismatch {
311 expected: num_values,
312 actual: sample_count,
313 });
314 }
315
316 for &sample in component.data() {
317 let raw = jpeg2000_raw_value(sample, params.packing.bits_per_value)?;
318 push_image_value(output, ¶ms.packing, raw)?;
319 }
320
321 Ok(())
322}
323
324#[cfg(not(feature = "jpeg2000"))]
325fn unpack_jpeg2000_into<T: DecodeSample>(
326 _data_bytes: &[u8],
327 _params: &Jpeg2000PackingParams,
328 _num_values: usize,
329 _output: &mut OutputCursor<'_, T>,
330) -> Result<()> {
331 Err(Error::UnsupportedDataTemplate(40))
332}
333
334#[cfg(feature = "jpeg2000")]
335fn validate_jpeg2000_bits(bits_per_value: u8) -> Result<()> {
336 if !(1..=32).contains(&bits_per_value) {
337 return Err(Error::UnsupportedPackingWidth(bits_per_value));
338 }
339 Ok(())
340}
341
342#[cfg(feature = "jpeg2000")]
343fn jpeg2000_raw_value(sample: i32, bits_per_value: u8) -> Result<u64> {
344 let raw = if bits_per_value == 32 {
345 u64::from(u32::from_ne_bytes(sample.to_ne_bytes()))
346 } else {
347 u64::try_from(sample).map_err(|_| {
348 Error::Other("JPEG 2000 unsigned component yielded a negative sample".into())
349 })?
350 };
351 validate_raw_value_fits(raw, bits_per_value)?;
352 Ok(raw)
353}
354
355#[cfg(feature = "png")]
356fn unpack_png_into<T: DecodeSample>(
357 data_bytes: &[u8],
358 params: &PngPackingParams,
359 num_values: usize,
360 output: &mut OutputCursor<'_, T>,
361) -> Result<()> {
362 validate_png_bits(params.packing.bits_per_value)?;
363
364 let decoder = png::Decoder::new(std::io::Cursor::new(data_bytes));
365 let mut reader = decoder
366 .read_info()
367 .map_err(|err| Error::Other(format!("PNG decode failed: {err}")))?;
368 let buffer_size = reader
369 .output_buffer_size()
370 .ok_or_else(|| Error::Other("PNG output buffer size overflow".into()))?;
371 let mut buffer = vec![0; buffer_size];
372 let info = reader
373 .next_frame(&mut buffer)
374 .map_err(|err| Error::Other(format!("PNG decode failed: {err}")))?;
375 let data = &buffer[..info.buffer_size()];
376
377 let sample_count = image_sample_count(info.width, info.height)?;
378 if sample_count != num_values {
379 return Err(Error::DataLengthMismatch {
380 expected: num_values,
381 actual: sample_count,
382 });
383 }
384
385 match (
386 info.color_type,
387 info.bit_depth,
388 params.packing.bits_per_value,
389 ) {
390 (png::ColorType::Grayscale, png::BitDepth::One, 1)
391 | (png::ColorType::Grayscale, png::BitDepth::Two, 2)
392 | (png::ColorType::Grayscale, png::BitDepth::Four, 4) => unpack_png_subbyte_grayscale(
393 data,
394 info.width,
395 info.height,
396 params.packing.bits_per_value,
397 ¶ms.packing,
398 output,
399 ),
400 (png::ColorType::Grayscale, png::BitDepth::Eight, 8) => {
401 unpack_png_bytes(data, 1, num_values, ¶ms.packing, output)
402 }
403 (png::ColorType::Grayscale, png::BitDepth::Sixteen, 16) => {
404 unpack_png_u16(data, num_values, ¶ms.packing, output)
405 }
406 (png::ColorType::Rgb, png::BitDepth::Eight, 24) => {
407 unpack_png_bytes(data, 3, num_values, ¶ms.packing, output)
408 }
409 (png::ColorType::Rgba, png::BitDepth::Eight, 32) => {
410 unpack_png_bytes(data, 4, num_values, ¶ms.packing, output)
411 }
412 (color_type, bit_depth, bits_per_value) => Err(Error::Other(format!(
413 "PNG image layout {color_type:?}/{bit_depth:?} is incompatible with GRIB bits-per-value {bits_per_value}"
414 ))),
415 }
416}
417
418#[cfg(not(feature = "png"))]
419fn unpack_png_into<T: DecodeSample>(
420 _data_bytes: &[u8],
421 _params: &PngPackingParams,
422 _num_values: usize,
423 _output: &mut OutputCursor<'_, T>,
424) -> Result<()> {
425 Err(Error::UnsupportedDataTemplate(41))
426}
427
428#[cfg(feature = "png")]
429fn validate_png_bits(bits_per_value: u8) -> Result<()> {
430 if !matches!(bits_per_value, 1 | 2 | 4 | 8 | 16 | 24 | 32) {
431 return Err(Error::UnsupportedPackingWidth(bits_per_value));
432 }
433 Ok(())
434}
435
436#[cfg(any(feature = "jpeg2000", feature = "png"))]
437fn image_sample_count(width: u32, height: u32) -> Result<usize> {
438 let width = usize::try_from(width).map_err(|_| Error::Other("image width overflow".into()))?;
439 let height =
440 usize::try_from(height).map_err(|_| Error::Other("image height overflow".into()))?;
441 width
442 .checked_mul(height)
443 .ok_or_else(|| Error::Other("image sample count overflow".into()))
444}
445
446#[cfg(feature = "png")]
447fn unpack_png_subbyte_grayscale<T: DecodeSample>(
448 data: &[u8],
449 width: u32,
450 height: u32,
451 bits_per_sample: u8,
452 params: &ImagePackingParams,
453 output: &mut OutputCursor<'_, T>,
454) -> Result<()> {
455 let width = usize::try_from(width).map_err(|_| Error::Other("PNG width overflow".into()))?;
456 let height = usize::try_from(height).map_err(|_| Error::Other("PNG height overflow".into()))?;
457 let bits = usize::from(bits_per_sample);
458 let row_bytes = width
459 .checked_mul(bits)
460 .ok_or_else(|| Error::Other("PNG row width overflow".into()))?
461 .div_ceil(8);
462 let expected_bytes = row_bytes
463 .checked_mul(height)
464 .ok_or_else(|| Error::Other("PNG data length overflow".into()))?;
465 if data.len() < expected_bytes {
466 return Err(Error::DataLengthMismatch {
467 expected: expected_bytes,
468 actual: data.len(),
469 });
470 }
471
472 let mask = (1u8 << bits) - 1;
473 for row in data[..expected_bytes].chunks_exact(row_bytes) {
474 for x in 0..width {
475 let bit_offset = x
476 .checked_mul(bits)
477 .ok_or_else(|| Error::Other("PNG bit offset overflow".into()))?;
478 let shift = 8 - bits - (bit_offset % 8);
479 let raw = u64::from((row[bit_offset / 8] >> shift) & mask);
480 push_image_value(output, params, raw)?;
481 }
482 }
483
484 Ok(())
485}
486
487#[cfg(feature = "png")]
488fn unpack_png_bytes<T: DecodeSample>(
489 data: &[u8],
490 bytes_per_sample: usize,
491 num_values: usize,
492 params: &ImagePackingParams,
493 output: &mut OutputCursor<'_, T>,
494) -> Result<()> {
495 let expected_bytes = num_values
496 .checked_mul(bytes_per_sample)
497 .ok_or_else(|| Error::Other("PNG data length overflow".into()))?;
498 if data.len() < expected_bytes {
499 return Err(Error::DataLengthMismatch {
500 expected: expected_bytes,
501 actual: data.len(),
502 });
503 }
504
505 for sample in data[..expected_bytes].chunks_exact(bytes_per_sample) {
506 let raw = sample
507 .iter()
508 .fold(0u64, |acc, byte| (acc << 8) | u64::from(*byte));
509 push_image_value(output, params, raw)?;
510 }
511
512 Ok(())
513}
514
515#[cfg(feature = "png")]
516fn unpack_png_u16<T: DecodeSample>(
517 data: &[u8],
518 num_values: usize,
519 params: &ImagePackingParams,
520 output: &mut OutputCursor<'_, T>,
521) -> Result<()> {
522 let expected_bytes = num_values
523 .checked_mul(2)
524 .ok_or_else(|| Error::Other("PNG data length overflow".into()))?;
525 if data.len() < expected_bytes {
526 return Err(Error::DataLengthMismatch {
527 expected: expected_bytes,
528 actual: data.len(),
529 });
530 }
531
532 for sample in data[..expected_bytes].chunks_exact(2) {
533 let raw = u64::from(u16::from_be_bytes(sample.try_into().unwrap()));
534 push_image_value(output, params, raw)?;
535 }
536
537 Ok(())
538}
539
540#[cfg(any(feature = "jpeg2000", feature = "png"))]
541fn push_image_value<T: DecodeSample>(
542 output: &mut OutputCursor<'_, T>,
543 params: &ImagePackingParams,
544 raw: u64,
545) -> Result<()> {
546 validate_raw_value_fits(raw, params.bits_per_value)?;
547 output.push_present(scale_image_value(params, raw))
548}
549
550#[cfg(any(feature = "jpeg2000", feature = "png"))]
551fn validate_raw_value_fits(raw: u64, bits_per_value: u8) -> Result<()> {
552 let max_value = if bits_per_value == u64::BITS as u8 {
553 u64::MAX
554 } else {
555 (1u64 << bits_per_value) - 1
556 };
557 if raw > max_value {
558 return Err(Error::Other(format!(
559 "decoded image sample {raw} exceeds GRIB bits-per-value {bits_per_value}"
560 )));
561 }
562 Ok(())
563}
564
565#[cfg(any(feature = "jpeg2000", feature = "png"))]
566fn scale_image_value<T: DecodeSample>(params: &ImagePackingParams, raw: u64) -> T {
567 let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
568 let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
569 T::from_f64(scale_decoded_value(
570 params.reference_value as f64,
571 raw as f64,
572 binary_factor,
573 decimal_factor,
574 ))
575}
576
577#[cfg(test)]
578fn unpack_complex(data_bytes: &[u8], params: &ComplexPackingParams) -> Result<Vec<f64>> {
579 let mut values = vec![0.0; params.encoded_values];
580 let mut output = OutputCursor::new(&mut values, None);
581 unpack_complex_into(data_bytes, params, &mut output)?;
582 output.finish()?;
583 Ok(values)
584}
585
586fn unpack_complex_into<T: DecodeSample>(
587 data_bytes: &[u8],
588 params: &ComplexPackingParams,
589 output: &mut OutputCursor<'_, T>,
590) -> Result<()> {
591 if params.num_groups == 0 {
592 return Err(Error::InvalidSection {
593 section: 5,
594 reason: "complex packing requires at least one group".into(),
595 });
596 }
597
598 let mut reader = BitReader::new(data_bytes);
599 let mut spatial = params
600 .spatial_differencing
601 .map(|spatial| read_spatial_descriptors(&mut reader, spatial))
602 .transpose()?
603 .map(SpatialRestoreState::new);
604
605 let layout = GroupReaderLayout::new(reader.bit_offset(), params)?;
606 let mut reference_reader = BitReader::with_offset(data_bytes, layout.reference_offset);
607 let mut width_reader = BitReader::with_offset(data_bytes, layout.width_offset);
608 let mut length_reader = BitReader::with_offset(data_bytes, layout.length_offset);
609 let mut value_reader = BitReader::with_offset(data_bytes, layout.value_offset);
610 let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
611 let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
612 let reference = params.reference_value as f64;
613 let mut actual_total = 0usize;
614
615 for group_index in 0..params.num_groups {
616 let group_reference = reference_reader.read(params.group_reference_bits as usize)?;
617 let width_delta = width_reader.read(params.group_width_bits as usize)?;
618 let group_width = usize::from(params.group_width_reference)
619 .checked_add(width_delta as usize)
620 .ok_or_else(|| Error::Other("group width overflow".into()))?;
621 let group_length = read_group_length(&mut length_reader, params, group_index)?;
622
623 actual_total = actual_total
624 .checked_add(group_length)
625 .ok_or_else(|| Error::Other("group length overflow".into()))?;
626
627 if group_width == 0 {
628 let raw_value = decode_constant_group_value(
629 group_reference,
630 params.group_reference_bits as usize,
631 params.missing_value_management,
632 )?;
633 for _ in 0..group_length {
634 let value = spatial
635 .as_mut()
636 .map_or(Ok(raw_value), |state| state.restore(raw_value))?;
637 output.push_present(scale_complex_value(
638 reference,
639 binary_factor,
640 decimal_factor,
641 value,
642 ))?;
643 }
644 continue;
645 }
646
647 if group_width > u64::BITS as usize {
648 return Err(Error::UnsupportedPackingWidth(group_width as u8));
649 }
650
651 let group_reference = i64::try_from(group_reference)
652 .map_err(|_| Error::Other("group reference exceeds i64 range".into()))?;
653 for _ in 0..group_length {
654 let packed = value_reader.read(group_width)?;
655 let value = decode_group_value(
656 group_reference,
657 packed,
658 group_width,
659 params.missing_value_management,
660 )?;
661 let value = spatial
662 .as_mut()
663 .map_or(Ok(value), |state| state.restore(value))?;
664 output.push_present(scale_complex_value(
665 reference,
666 binary_factor,
667 decimal_factor,
668 value,
669 ))?;
670 }
671 }
672
673 if actual_total != params.encoded_values {
674 return Err(Error::DataLengthMismatch {
675 expected: params.encoded_values,
676 actual: actual_total,
677 });
678 }
679
680 if output.values_written() != params.encoded_values {
681 return Err(Error::DataLengthMismatch {
682 expected: params.encoded_values,
683 actual: output.values_written(),
684 });
685 }
686
687 if let Some(spatial) = spatial {
688 spatial.finish()?;
689 }
690
691 Ok(())
692}
693
694fn read_group_length(
695 reader: &mut BitReader<'_>,
696 params: &ComplexPackingParams,
697 group_index: usize,
698) -> Result<usize> {
699 if params.scaled_group_length_bits as usize > u64::BITS as usize {
700 return Err(Error::UnsupportedPackingWidth(
701 params.scaled_group_length_bits,
702 ));
703 }
704
705 if group_index + 1 == params.num_groups {
706 return Ok(params.true_length_last_group as usize);
707 }
708
709 let scaled = reader
710 .read(params.scaled_group_length_bits as usize)?
711 .checked_mul(u64::from(params.group_length_increment))
712 .ok_or_else(|| Error::Other("group length overflow".into()))?;
713 let length = u64::from(params.group_length_reference)
714 .checked_add(scaled)
715 .ok_or_else(|| Error::Other("group length overflow".into()))?;
716 usize::try_from(length).map_err(|_| Error::Other("group length overflow".into()))
717}
718
719fn read_spatial_descriptors(
720 reader: &mut BitReader<'_>,
721 params: SpatialDifferencingParams,
722) -> Result<SpatialDescriptors> {
723 if params.descriptor_octets == 0 {
724 return Err(Error::InvalidSection {
725 section: 5,
726 reason: "spatial differencing requires at least one descriptor octet".into(),
727 });
728 }
729
730 let bit_count = usize::from(params.descriptor_octets) * 8;
731 if bit_count > u64::BITS as usize {
732 return Err(Error::Other(
733 "spatial differencing descriptors wider than 8 octets are not supported".into(),
734 ));
735 }
736
737 let first_value = reader.read_signed(bit_count)?;
738 let second_value = if params.order == 2 {
739 Some(reader.read_signed(bit_count)?)
740 } else {
741 None
742 };
743 for _ in usize::from(params.order.min(2))..params.order as usize {
744 let _ = reader.read_signed(bit_count)?;
745 }
746 let overall_minimum = reader.read_signed(bit_count)?;
747
748 Ok(SpatialDescriptors {
749 order: params.order,
750 first_value,
751 second_value,
752 overall_minimum,
753 })
754}
755
756fn decode_constant_group_value(
757 group_reference: u64,
758 group_reference_bits: usize,
759 missing_value_management: u8,
760) -> Result<Option<i64>> {
761 if is_missing_code(
762 group_reference,
763 group_reference_bits,
764 missing_value_management,
765 MissingKind::Primary,
766 )? || is_missing_code(
767 group_reference,
768 group_reference_bits,
769 missing_value_management,
770 MissingKind::Secondary,
771 )? {
772 return Ok(None);
773 }
774
775 let value = i64::try_from(group_reference)
776 .map_err(|_| Error::Other("group reference exceeds i64 range".into()))?;
777 Ok(Some(value))
778}
779
780fn decode_group_value(
781 group_reference: i64,
782 packed: u64,
783 group_width: usize,
784 missing_value_management: u8,
785) -> Result<Option<i64>> {
786 if is_missing_code(
787 packed,
788 group_width,
789 missing_value_management,
790 MissingKind::Primary,
791 )? || is_missing_code(
792 packed,
793 group_width,
794 missing_value_management,
795 MissingKind::Secondary,
796 )? {
797 return Ok(None);
798 }
799
800 let packed =
801 i64::try_from(packed).map_err(|_| Error::Other("packed value exceeds i64 range".into()))?;
802 let value = group_reference
803 .checked_add(packed)
804 .ok_or_else(|| Error::Other("decoded complex packing value overflow".into()))?;
805 Ok(Some(value))
806}
807
808fn is_missing_code(
809 value: u64,
810 bit_width: usize,
811 missing_value_management: u8,
812 kind: MissingKind,
813) -> Result<bool> {
814 let required_mode = match kind {
815 MissingKind::Primary => 1,
816 MissingKind::Secondary => 2,
817 };
818 if missing_value_management < required_mode {
819 return Ok(false);
820 }
821
822 let Some(code) = missing_code(bit_width, kind)? else {
823 return Ok(false);
824 };
825 Ok(value == code)
826}
827
828fn missing_code(bit_width: usize, kind: MissingKind) -> Result<Option<u64>> {
829 if bit_width == 0 {
830 return Ok(None);
831 }
832 if bit_width > u64::BITS as usize {
833 return Err(Error::UnsupportedPackingWidth(bit_width as u8));
834 }
835
836 let max_value = if bit_width == u64::BITS as usize {
837 u64::MAX
838 } else {
839 (1u64 << bit_width) - 1
840 };
841
842 let code = match kind {
843 MissingKind::Primary => max_value,
844 MissingKind::Secondary => max_value.saturating_sub(1),
845 };
846 Ok(Some(code))
847}
848
849fn scale_complex_value<T: DecodeSample>(
850 reference: f64,
851 binary_factor: f64,
852 decimal_factor: f64,
853 value: Option<i64>,
854) -> T {
855 match value {
856 Some(value) => T::from_f64(scale_decoded_value(
857 reference,
858 value as f64,
859 binary_factor,
860 decimal_factor,
861 )),
862 None => T::nan(),
863 }
864}
865
866fn scale_decoded_value(
867 reference: f64,
868 packed_delta: f64,
869 binary_factor: f64,
870 decimal_factor: f64,
871) -> f64 {
872 (reference + packed_delta * binary_factor) * decimal_factor
873}
874
875fn bitmap_bit(bitmap_payload: &[u8], index: usize) -> Result<bool> {
876 read_bit(bitmap_payload, index).map_err(|_| Error::DataLengthMismatch {
877 expected: index / 8 + 1,
878 actual: bitmap_payload.len(),
879 })
880}
881
882struct GroupReaderLayout {
883 reference_offset: usize,
884 width_offset: usize,
885 length_offset: usize,
886 value_offset: usize,
887}
888
889impl GroupReaderLayout {
890 fn new(start_bit_offset: usize, params: &ComplexPackingParams) -> Result<Self> {
891 if params.group_reference_bits as usize > u64::BITS as usize {
892 return Err(Error::UnsupportedPackingWidth(params.group_reference_bits));
893 }
894 if params.group_width_bits as usize > u64::BITS as usize {
895 return Err(Error::UnsupportedPackingWidth(params.group_width_bits));
896 }
897 if params.scaled_group_length_bits as usize > u64::BITS as usize {
898 return Err(Error::UnsupportedPackingWidth(
899 params.scaled_group_length_bits,
900 ));
901 }
902
903 let reference_offset = start_bit_offset;
904 let width_offset = align_bit_offset(add_group_bits(
905 reference_offset,
906 params.num_groups,
907 params.group_reference_bits as usize,
908 )?)?;
909 let length_offset = align_bit_offset(add_group_bits(
910 width_offset,
911 params.num_groups,
912 params.group_width_bits as usize,
913 )?)?;
914 let value_offset = align_bit_offset(add_group_bits(
915 length_offset,
916 params.num_groups,
917 params.scaled_group_length_bits as usize,
918 )?)?;
919
920 Ok(Self {
921 reference_offset,
922 width_offset,
923 length_offset,
924 value_offset,
925 })
926 }
927}
928
929fn add_group_bits(start_bit_offset: usize, count: usize, bits_per_group: usize) -> Result<usize> {
930 count
931 .checked_mul(bits_per_group)
932 .and_then(|total_bits| start_bit_offset.checked_add(total_bits))
933 .ok_or_else(|| Error::Other("bit offset overflow".into()))
934}
935
936fn align_bit_offset(bit_offset: usize) -> Result<usize> {
937 let remainder = bit_offset % 8;
938 if remainder == 0 {
939 Ok(bit_offset)
940 } else {
941 bit_offset
942 .checked_add(8 - remainder)
943 .ok_or_else(|| Error::Other("bit offset overflow".into()))
944 }
945}
946
947struct OutputCursor<'a, T> {
948 output: &'a mut [T],
949 bitmap: Option<&'a [u8]>,
950 next_index: usize,
951 values_written: usize,
952}
953
954impl<'a, T: DecodeSample> OutputCursor<'a, T> {
955 fn new(output: &'a mut [T], bitmap: Option<&'a [u8]>) -> Self {
956 Self {
957 output,
958 bitmap,
959 next_index: 0,
960 values_written: 0,
961 }
962 }
963
964 fn push_present(&mut self, value: T) -> Result<()> {
965 match self.bitmap {
966 Some(bitmap) => {
967 while self.next_index < self.output.len() {
968 if bitmap_bit(bitmap, self.next_index)? {
969 self.output[self.next_index] = value;
970 self.next_index += 1;
971 self.values_written += 1;
972 return Ok(());
973 }
974
975 self.output[self.next_index] = T::nan();
976 self.next_index += 1;
977 }
978
979 let expected = count_bitmap_present_points(bitmap, self.output.len())?;
980 Err(Error::DataLengthMismatch {
981 expected,
982 actual: self.values_written + 1,
983 })
984 }
985 None => {
986 if self.next_index >= self.output.len() {
987 return Err(Error::DataLengthMismatch {
988 expected: self.output.len(),
989 actual: self.next_index + 1,
990 });
991 }
992
993 self.output[self.next_index] = value;
994 self.next_index += 1;
995 self.values_written += 1;
996 Ok(())
997 }
998 }
999 }
1000
1001 fn finish(mut self) -> Result<()> {
1002 if let Some(bitmap) = self.bitmap {
1003 while self.next_index < self.output.len() {
1004 if bitmap_bit(bitmap, self.next_index)? {
1005 return Err(Error::DataLengthMismatch {
1006 expected: count_bitmap_present_points(bitmap, self.output.len())?,
1007 actual: self.values_written,
1008 });
1009 }
1010 self.output[self.next_index] = T::nan();
1011 self.next_index += 1;
1012 }
1013 }
1014
1015 if self.next_index != self.output.len() {
1016 return Err(Error::DataLengthMismatch {
1017 expected: self.output.len(),
1018 actual: self.next_index,
1019 });
1020 }
1021
1022 Ok(())
1023 }
1024 fn values_written(&self) -> usize {
1025 self.values_written
1026 }
1027}
1028
1029#[derive(Debug, Clone)]
1030struct SpatialDescriptors {
1031 order: u8,
1032 first_value: i64,
1033 second_value: Option<i64>,
1034 overall_minimum: i64,
1035}
1036
1037#[derive(Debug, Clone)]
1038struct SpatialRestoreState {
1039 descriptors: SpatialDescriptors,
1040 previous: Option<i64>,
1041 previous_difference: Option<i64>,
1042 non_missing_seen: usize,
1043}
1044
1045impl SpatialRestoreState {
1046 fn new(descriptors: SpatialDescriptors) -> Self {
1047 Self {
1048 descriptors,
1049 previous: None,
1050 previous_difference: None,
1051 non_missing_seen: 0,
1052 }
1053 }
1054
1055 fn restore(&mut self, value: Option<i64>) -> Result<Option<i64>> {
1056 let Some(value) = value else {
1057 return Ok(None);
1058 };
1059
1060 let restored = match self.descriptors.order {
1061 1 => self.restore_first_order(value)?,
1062 2 => self.restore_second_order(value)?,
1063 other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
1064 };
1065
1066 self.previous = Some(restored);
1067 self.non_missing_seen += 1;
1068 Ok(Some(restored))
1069 }
1070
1071 fn finish(self) -> Result<()> {
1072 let expected = match self.descriptors.order {
1073 1 => 1,
1074 2 => 2,
1075 other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
1076 };
1077 if self.non_missing_seen < expected {
1078 return Err(Error::DataLengthMismatch {
1079 expected,
1080 actual: self.non_missing_seen,
1081 });
1082 }
1083 Ok(())
1084 }
1085
1086 fn restore_first_order(&mut self, value: i64) -> Result<i64> {
1087 if self.non_missing_seen == 0 {
1088 return Ok(self.descriptors.first_value);
1089 }
1090
1091 let delta = value
1092 .checked_add(self.descriptors.overall_minimum)
1093 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1094 self.previous
1095 .and_then(|previous| previous.checked_add(delta))
1096 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))
1097 }
1098
1099 fn restore_second_order(&mut self, value: i64) -> Result<i64> {
1100 match self.non_missing_seen {
1101 0 => Ok(self.descriptors.first_value),
1102 1 => {
1103 let second_value = self.descriptors.second_value.ok_or(Error::InvalidSection {
1104 section: 5,
1105 reason: "missing second-order spatial differencing descriptors".into(),
1106 })?;
1107 self.previous_difference = second_value.checked_sub(self.descriptors.first_value);
1108 self.previous_difference
1109 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1110 Ok(second_value)
1111 }
1112 _ => {
1113 let second_difference = value
1114 .checked_add(self.descriptors.overall_minimum)
1115 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1116 let difference = self
1117 .previous_difference
1118 .and_then(|previous_difference| {
1119 previous_difference.checked_add(second_difference)
1120 })
1121 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1122 let next = self
1123 .previous
1124 .and_then(|previous| previous.checked_add(difference))
1125 .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1126 self.previous_difference = Some(difference);
1127 Ok(next)
1128 }
1129 }
1130 }
1131}
1132
1133#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1134enum MissingKind {
1135 Primary,
1136 Secondary,
1137}
1138
1139#[cfg(test)]
1140mod tests {
1141 use super::{
1142 bitmap_payload, count_bitmap_present_points, decode_field, decode_payload, unpack_complex,
1143 unpack_simple, ComplexPackingParams, DataRepresentation, ImagePackingParams,
1144 PngPackingParams, SimplePackingParams, SpatialDifferencingParams,
1145 };
1146 use crate::error::Error;
1147
1148 #[test]
1149 fn unpack_simple_constant() {
1150 let params = SimplePackingParams {
1151 encoded_values: 5,
1152 reference_value: 42.0,
1153 binary_scale: 0,
1154 decimal_scale: 0,
1155 bits_per_value: 0,
1156 original_field_type: 0,
1157 };
1158 let values = unpack_simple(&[], ¶ms, 5).unwrap();
1159 assert_eq!(values, vec![42.0; 5]);
1160 }
1161
1162 #[test]
1163 fn unpack_simple_basic() {
1164 let params = SimplePackingParams {
1165 encoded_values: 5,
1166 reference_value: 0.0,
1167 binary_scale: 0,
1168 decimal_scale: 0,
1169 bits_per_value: 8,
1170 original_field_type: 0,
1171 };
1172 let values = unpack_simple(&[0, 1, 2, 3, 4], ¶ms, 5).unwrap();
1173 assert_eq!(values, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
1174 }
1175
1176 #[test]
1177 fn unpack_simple_applies_decimal_scale_to_reference_and_values() {
1178 let params = SimplePackingParams {
1179 encoded_values: 2,
1180 reference_value: 10.0,
1181 binary_scale: 0,
1182 decimal_scale: 1,
1183 bits_per_value: 8,
1184 original_field_type: 0,
1185 };
1186
1187 let values = unpack_simple(&[0, 20], ¶ms, 2).unwrap();
1188 assert!((values[0] - 1.0).abs() < 1e-12);
1189 assert!((values[1] - 3.0).abs() < 1e-12);
1190 }
1191
1192 #[test]
1193 fn decodes_bitmap_masked_field() {
1194 let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
1195 let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
1196 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
1197 encoded_values: 3,
1198 reference_value: 0.0,
1199 binary_scale: 0,
1200 decimal_scale: 0,
1201 bits_per_value: 8,
1202 original_field_type: 0,
1203 });
1204
1205 let bitmap = bitmap_payload(&bitmap_section).unwrap();
1206 let decoded = decode_field(&data_section, &representation, bitmap, 4).unwrap();
1207 assert_eq!(decoded[0], 10.0);
1208 assert!(decoded[1].is_nan());
1209 assert_eq!(decoded[2], 20.0);
1210 assert_eq!(decoded[3], 30.0);
1211 }
1212
1213 #[cfg(feature = "png")]
1214 #[test]
1215 fn decodes_png_packing_grayscale8() {
1216 let payload = encode_png(
1217 2,
1218 2,
1219 png::ColorType::Grayscale,
1220 png::BitDepth::Eight,
1221 &[1, 2, 3, 4],
1222 );
1223 let representation = DataRepresentation::PngPacking(PngPackingParams {
1224 packing: ImagePackingParams {
1225 encoded_values: 4,
1226 reference_value: 10.0,
1227 binary_scale: 1,
1228 decimal_scale: 1,
1229 bits_per_value: 8,
1230 original_field_type: 0,
1231 },
1232 });
1233
1234 let decoded = decode_payload(&payload, &representation, None, 4).unwrap();
1235 assert_float_values(&decoded, &[1.2, 1.4, 1.6, 1.8]);
1236 }
1237
1238 #[cfg(feature = "png")]
1239 #[test]
1240 fn decodes_png_packing_grayscale16() {
1241 let payload = encode_png(
1242 2,
1243 1,
1244 png::ColorType::Grayscale,
1245 png::BitDepth::Sixteen,
1246 &[0x01, 0x00, 0x02, 0x00],
1247 );
1248 let representation = DataRepresentation::PngPacking(PngPackingParams {
1249 packing: ImagePackingParams {
1250 encoded_values: 2,
1251 reference_value: 0.0,
1252 binary_scale: 0,
1253 decimal_scale: 0,
1254 bits_per_value: 16,
1255 original_field_type: 0,
1256 },
1257 });
1258
1259 let decoded = decode_payload(&payload, &representation, None, 2).unwrap();
1260 assert_eq!(decoded, vec![256.0, 512.0]);
1261 }
1262
1263 #[cfg(feature = "png")]
1264 #[test]
1265 fn decodes_png_packing_grayscale_subbyte() {
1266 let payload = encode_png(
1267 4,
1268 1,
1269 png::ColorType::Grayscale,
1270 png::BitDepth::Four,
1271 &[0x12, 0x34],
1272 );
1273 let representation = DataRepresentation::PngPacking(PngPackingParams {
1274 packing: ImagePackingParams {
1275 encoded_values: 4,
1276 reference_value: 0.0,
1277 binary_scale: 0,
1278 decimal_scale: 0,
1279 bits_per_value: 4,
1280 original_field_type: 0,
1281 },
1282 });
1283
1284 let decoded = decode_payload(&payload, &representation, None, 4).unwrap();
1285 assert_eq!(decoded, vec![1.0, 2.0, 3.0, 4.0]);
1286 }
1287
1288 #[cfg(feature = "png")]
1289 #[test]
1290 fn decodes_png_packing_rgb8() {
1291 let payload = encode_png(
1292 2,
1293 1,
1294 png::ColorType::Rgb,
1295 png::BitDepth::Eight,
1296 &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
1297 );
1298 let representation = DataRepresentation::PngPacking(PngPackingParams {
1299 packing: ImagePackingParams {
1300 encoded_values: 2,
1301 reference_value: 0.0,
1302 binary_scale: 0,
1303 decimal_scale: 0,
1304 bits_per_value: 24,
1305 original_field_type: 0,
1306 },
1307 });
1308
1309 let decoded = decode_payload(&payload, &representation, None, 2).unwrap();
1310 assert_eq!(decoded, vec![0x01_02_03 as f64, 0x04_05_06 as f64]);
1311 }
1312
1313 #[cfg(feature = "png")]
1314 #[test]
1315 fn decodes_png_packing_rgba8() {
1316 let payload = encode_png(
1317 1,
1318 1,
1319 png::ColorType::Rgba,
1320 png::BitDepth::Eight,
1321 &[0x01, 0x02, 0x03, 0x04],
1322 );
1323 let representation = DataRepresentation::PngPacking(PngPackingParams {
1324 packing: ImagePackingParams {
1325 encoded_values: 1,
1326 reference_value: 0.0,
1327 binary_scale: 0,
1328 decimal_scale: 0,
1329 bits_per_value: 32,
1330 original_field_type: 0,
1331 },
1332 });
1333
1334 let decoded = decode_payload(&payload, &representation, None, 1).unwrap();
1335 assert_eq!(decoded, vec![0x01_02_03_04 as f64]);
1336 }
1337
1338 #[cfg(feature = "png")]
1339 #[test]
1340 fn decodes_png_packing_with_bitmap() {
1341 let payload = encode_png(
1342 3,
1343 1,
1344 png::ColorType::Grayscale,
1345 png::BitDepth::Eight,
1346 &[10, 20, 30],
1347 );
1348 let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
1349 let representation = DataRepresentation::PngPacking(PngPackingParams {
1350 packing: ImagePackingParams {
1351 encoded_values: 3,
1352 reference_value: 0.0,
1353 binary_scale: 0,
1354 decimal_scale: 0,
1355 bits_per_value: 8,
1356 original_field_type: 0,
1357 },
1358 });
1359
1360 let decoded = decode_payload(
1361 &payload,
1362 &representation,
1363 bitmap_payload(&bitmap_section).unwrap(),
1364 4,
1365 )
1366 .unwrap();
1367 assert_eq!(decoded[0], 10.0);
1368 assert!(decoded[1].is_nan());
1369 assert_eq!(decoded[2], 20.0);
1370 assert_eq!(decoded[3], 30.0);
1371 }
1372
1373 #[cfg(not(feature = "png"))]
1374 #[test]
1375 fn png_packing_requires_png_feature() {
1376 let representation = DataRepresentation::PngPacking(PngPackingParams {
1377 packing: ImagePackingParams {
1378 encoded_values: 1,
1379 reference_value: 0.0,
1380 binary_scale: 0,
1381 decimal_scale: 0,
1382 bits_per_value: 8,
1383 original_field_type: 0,
1384 },
1385 });
1386
1387 let err = decode_payload(&[], &representation, None, 1).unwrap_err();
1388 assert!(matches!(err, Error::UnsupportedDataTemplate(41)));
1389 }
1390
1391 #[cfg(not(feature = "jpeg2000"))]
1392 #[test]
1393 fn jpeg2000_packing_requires_jpeg2000_feature() {
1394 let representation = DataRepresentation::Jpeg2000Packing(super::Jpeg2000PackingParams {
1395 packing: ImagePackingParams {
1396 encoded_values: 1,
1397 reference_value: 0.0,
1398 binary_scale: 0,
1399 decimal_scale: 0,
1400 bits_per_value: 8,
1401 original_field_type: 0,
1402 },
1403 compression_type: 1,
1404 target_compression_ratio: 255,
1405 });
1406
1407 let err = decode_payload(&[], &representation, None, 1).unwrap_err();
1408 assert!(matches!(err, Error::UnsupportedDataTemplate(40)));
1409 }
1410
1411 #[test]
1412 fn rejects_simple_packing_wider_than_u64() {
1413 let params = SimplePackingParams {
1414 encoded_values: 1,
1415 reference_value: 0.0,
1416 binary_scale: 0,
1417 decimal_scale: 0,
1418 bits_per_value: 65,
1419 original_field_type: 0,
1420 };
1421 let err = unpack_simple(&[0; 9], ¶ms, 1).unwrap_err();
1422 assert!(matches!(err, Error::UnsupportedPackingWidth(65)));
1423 }
1424
1425 #[test]
1426 fn rejects_encoded_value_count_mismatch_without_bitmap() {
1427 let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
1428 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
1429 encoded_values: 3,
1430 reference_value: 0.0,
1431 binary_scale: 0,
1432 decimal_scale: 0,
1433 bits_per_value: 8,
1434 original_field_type: 0,
1435 });
1436
1437 let err = decode_field(&data_section, &representation, None, 4).unwrap_err();
1438 assert!(matches!(
1439 err,
1440 Error::DataLengthMismatch {
1441 expected: 4,
1442 actual: 3,
1443 }
1444 ));
1445 }
1446
1447 #[test]
1448 fn rejects_bitmap_present_count_mismatch() {
1449 let data_section = [0, 0, 0, 7, 7, 10, 20];
1450 let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
1451 let representation = DataRepresentation::SimplePacking(SimplePackingParams {
1452 encoded_values: 2,
1453 reference_value: 0.0,
1454 binary_scale: 0,
1455 decimal_scale: 0,
1456 bits_per_value: 8,
1457 original_field_type: 0,
1458 });
1459
1460 let bitmap = bitmap_payload(&bitmap_section).unwrap();
1461 let err = decode_field(&data_section, &representation, bitmap, 4).unwrap_err();
1462 assert!(matches!(
1463 err,
1464 Error::DataLengthMismatch {
1465 expected: 3,
1466 actual: 2,
1467 }
1468 ));
1469 }
1470
1471 #[test]
1472 fn counts_bitmap_present_points_with_partial_bytes() {
1473 let present = count_bitmap_present_points(&[0b1011_1111], 3).unwrap();
1474 assert_eq!(present, 2);
1475 }
1476
1477 #[test]
1478 fn unpacks_complex_packing_with_explicit_missing() {
1479 let params = ComplexPackingParams {
1480 encoded_values: 4,
1481 reference_value: 0.0,
1482 binary_scale: 0,
1483 decimal_scale: 0,
1484 group_reference_bits: 4,
1485 original_field_type: 0,
1486 group_splitting_method: 1,
1487 missing_value_management: 1,
1488 primary_missing_substitute: u32::MAX,
1489 secondary_missing_substitute: u32::MAX,
1490 num_groups: 2,
1491 group_width_reference: 0,
1492 group_width_bits: 2,
1493 group_length_reference: 2,
1494 group_length_increment: 1,
1495 true_length_last_group: 2,
1496 scaled_group_length_bits: 0,
1497 spatial_differencing: None,
1498 };
1499
1500 let values = unpack_complex(&[0x79, 0x90, 0x34], ¶ms).unwrap();
1501 assert_eq!(values[0], 7.0);
1502 assert!(values[1].is_nan());
1503 assert_eq!(values[2], 9.0);
1504 assert!(values[3].is_nan());
1505 }
1506
1507 #[test]
1508 fn unpacks_complex_packing_applies_decimal_scale_to_reference_and_values() {
1509 let params = ComplexPackingParams {
1510 encoded_values: 2,
1511 reference_value: 10.0,
1512 binary_scale: 0,
1513 decimal_scale: 1,
1514 group_reference_bits: 4,
1515 original_field_type: 0,
1516 group_splitting_method: 1,
1517 missing_value_management: 0,
1518 primary_missing_substitute: u32::MAX,
1519 secondary_missing_substitute: u32::MAX,
1520 num_groups: 1,
1521 group_width_reference: 4,
1522 group_width_bits: 0,
1523 group_length_reference: 2,
1524 group_length_increment: 1,
1525 true_length_last_group: 2,
1526 scaled_group_length_bits: 0,
1527 spatial_differencing: None,
1528 };
1529
1530 let values = unpack_complex(&[0x10, 0x02], ¶ms).unwrap();
1531 assert!((values[0] - 1.1).abs() < 1e-12);
1532 assert!((values[1] - 1.3).abs() < 1e-12);
1533 }
1534
1535 #[test]
1536 fn unpacks_complex_packing_with_second_order_spatial_differencing() {
1537 let params = ComplexPackingParams {
1538 encoded_values: 4,
1539 reference_value: 0.0,
1540 binary_scale: 0,
1541 decimal_scale: 0,
1542 group_reference_bits: 1,
1543 original_field_type: 0,
1544 group_splitting_method: 1,
1545 missing_value_management: 0,
1546 primary_missing_substitute: u32::MAX,
1547 secondary_missing_substitute: u32::MAX,
1548 num_groups: 1,
1549 group_width_reference: 1,
1550 group_width_bits: 0,
1551 group_length_reference: 4,
1552 group_length_increment: 1,
1553 true_length_last_group: 4,
1554 scaled_group_length_bits: 0,
1555 spatial_differencing: Some(SpatialDifferencingParams {
1556 order: 2,
1557 descriptor_octets: 2,
1558 }),
1559 };
1560
1561 let values =
1562 unpack_complex(&[0x00, 0x0A, 0x00, 0x0D, 0x00, 0x03, 0x00, 0x10], ¶ms).unwrap();
1563 assert_eq!(values, vec![10.0, 13.0, 19.0, 29.0]);
1564 }
1565
1566 #[test]
1567 fn unpacks_complex_packing_with_spatial_differencing_and_missing_values() {
1568 let params = ComplexPackingParams {
1569 encoded_values: 4,
1570 reference_value: 0.0,
1571 binary_scale: 0,
1572 decimal_scale: 0,
1573 group_reference_bits: 1,
1574 original_field_type: 0,
1575 group_splitting_method: 1,
1576 missing_value_management: 1,
1577 primary_missing_substitute: u32::MAX,
1578 secondary_missing_substitute: u32::MAX,
1579 num_groups: 1,
1580 group_width_reference: 2,
1581 group_width_bits: 0,
1582 group_length_reference: 4,
1583 group_length_increment: 1,
1584 true_length_last_group: 4,
1585 scaled_group_length_bits: 0,
1586 spatial_differencing: Some(SpatialDifferencingParams {
1587 order: 1,
1588 descriptor_octets: 2,
1589 }),
1590 };
1591
1592 let values = unpack_complex(&[0x00, 0x0A, 0x00, 0x03, 0x00, 0x32], ¶ms).unwrap();
1593 assert_eq!(values[0], 10.0);
1594 assert!(values[1].is_nan());
1595 assert_eq!(values[2], 13.0);
1596 assert_eq!(values[3], 18.0);
1597 }
1598
1599 #[cfg(feature = "png")]
1600 fn encode_png(
1601 width: u32,
1602 height: u32,
1603 color_type: png::ColorType,
1604 bit_depth: png::BitDepth,
1605 data: &[u8],
1606 ) -> Vec<u8> {
1607 let mut payload = Vec::new();
1608 {
1609 let mut encoder = png::Encoder::new(&mut payload, width, height);
1610 encoder.set_color(color_type);
1611 encoder.set_depth(bit_depth);
1612 let mut writer = encoder.write_header().unwrap();
1613 writer.write_image_data(data).unwrap();
1614 }
1615 payload
1616 }
1617
1618 #[cfg(feature = "png")]
1619 fn assert_float_values(actual: &[f64], expected: &[f64]) {
1620 assert_eq!(actual.len(), expected.len());
1621 for (actual, expected) in actual.iter().zip(expected) {
1622 assert!(
1623 (actual - expected).abs() < 1e-12,
1624 "expected {expected}, got {actual}"
1625 );
1626 }
1627 }
1628}