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