Skip to main content

grib_reader/
data.rs

1//! Data Section (Section 7) decoding.
2
3use 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
10/// Numeric target type for decoded field values.
11pub 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
36/// Decode Section 7 payload into field values, applying Section 6 bitmap when present.
37pub 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
58/// Decode Section 7 payload into a caller-provided buffer, applying Section 6
59/// bitmap when present.
60pub 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
161/// Parse bitmap presence from Section 6.
162pub 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(&section_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
209/// Unpack simple-packed values.
210pub 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, &params.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            &params.packing,
398            output,
399        ),
400        (png::ColorType::Grayscale, png::BitDepth::Eight, 8) => {
401            unpack_png_bytes(data, 1, num_values, &params.packing, output)
402        }
403        (png::ColorType::Grayscale, png::BitDepth::Sixteen, 16) => {
404            unpack_png_u16(data, num_values, &params.packing, output)
405        }
406        (png::ColorType::Rgb, png::BitDepth::Eight, 24) => {
407            unpack_png_bytes(data, 3, num_values, &params.packing, output)
408        }
409        (png::ColorType::Rgba, png::BitDepth::Eight, 32) => {
410            unpack_png_bytes(data, 4, num_values, &params.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(&[], &params, 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], &params, 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], &params, 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], &params, 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], &params).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], &params).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], &params).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], &params).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}