Skip to main content

grib_reader/
data.rs

1//! Data Section (Section 7) decoding.
2
3use crate::error::{Error, Result};
4use grib_core::binary::decode_ieee_binary128;
5use grib_core::bit::BitReader;
6pub use grib_core::data::{
7    CcsdsBlockSize, CcsdsFlags, CcsdsPackingParams, ComplexPackingParams, DataRepresentation,
8    Grib1SecondOrderLayout, Grib1SecondOrderPackingParams, IeeePackingParams, IeeePrecision,
9    Jpeg2000PackingParams, PngPackingParams, RunLengthPackingParams, ScaledPackingParams,
10    SpatialDifferencingParams,
11};
12use grib_core::filled_vec;
13
14#[cfg(feature = "ccsds")]
15use grib_aec::{decode as aec_decode, AecFlags, AecParams};
16
17/// Numeric target type for decoded field values.
18pub trait DecodeSample: Copy + Sized {
19    fn from_f64(value: f64) -> Self;
20    fn nan() -> Self;
21}
22
23impl DecodeSample for f32 {
24    fn from_f64(value: f64) -> Self {
25        value as f32
26    }
27
28    fn nan() -> Self {
29        f32::NAN
30    }
31}
32
33impl DecodeSample for f64 {
34    fn from_f64(value: f64) -> Self {
35        value
36    }
37
38    fn nan() -> Self {
39        f64::NAN
40    }
41}
42
43/// Decode Section 7 payload into field values, applying Section 6 bitmap when present.
44pub fn decode_field(
45    data_section: &[u8],
46    representation: &DataRepresentation,
47    bitmap_section: Option<&[u8]>,
48    num_grid_points: usize,
49) -> Result<Vec<f64>> {
50    if data_section.len() < 5 || data_section[4] != 7 {
51        return Err(Error::InvalidSection {
52            section: data_section.get(4).copied().unwrap_or(7),
53            reason: "not a data section".into(),
54        });
55    }
56
57    decode_payload(
58        &data_section[5..],
59        representation,
60        bitmap_section,
61        num_grid_points,
62    )
63}
64
65/// Decode Section 7 payload into a caller-provided buffer, applying Section 6
66/// bitmap when present.
67pub fn decode_field_into<T: DecodeSample>(
68    data_section: &[u8],
69    representation: &DataRepresentation,
70    bitmap_section: Option<&[u8]>,
71    num_grid_points: usize,
72    out: &mut [T],
73) -> Result<()> {
74    if data_section.len() < 5 || data_section[4] != 7 {
75        return Err(Error::InvalidSection {
76            section: data_section.get(4).copied().unwrap_or(7),
77            reason: "not a data section".into(),
78        });
79    }
80
81    decode_payload_into_with_group_lengths(
82        &data_section[5..],
83        representation,
84        bitmap_section,
85        num_grid_points,
86        out,
87        None,
88    )
89}
90
91pub(crate) fn decode_field_into_with_group_lengths<T: DecodeSample>(
92    data_section: &[u8],
93    representation: &DataRepresentation,
94    bitmap_section: Option<&[u8]>,
95    num_grid_points: usize,
96    out: &mut [T],
97    row_group_lengths: Option<&[usize]>,
98) -> Result<()> {
99    if data_section.len() < 5 || data_section[4] != 7 {
100        return Err(Error::InvalidSection {
101            section: data_section.get(4).copied().unwrap_or(7),
102            reason: "not a data section".into(),
103        });
104    }
105
106    decode_payload_into_with_group_lengths(
107        &data_section[5..],
108        representation,
109        bitmap_section,
110        num_grid_points,
111        out,
112        row_group_lengths,
113    )
114}
115
116pub(crate) fn decode_payload(
117    payload: &[u8],
118    representation: &DataRepresentation,
119    bitmap_section: Option<&[u8]>,
120    num_grid_points: usize,
121) -> Result<Vec<f64>> {
122    let mut values = filled_vec(num_grid_points, 0.0, "decoded field")?;
123    decode_payload_into_with_group_lengths(
124        payload,
125        representation,
126        bitmap_section,
127        num_grid_points,
128        &mut values,
129        None,
130    )?;
131    Ok(values)
132}
133
134pub(crate) fn decode_payload_into_with_group_lengths<T: DecodeSample>(
135    payload: &[u8],
136    representation: &DataRepresentation,
137    bitmap_section: Option<&[u8]>,
138    num_grid_points: usize,
139    out: &mut [T],
140    row_group_lengths: Option<&[usize]>,
141) -> Result<()> {
142    if out.len() != num_grid_points {
143        return Err(Error::DataLengthMismatch {
144            expected: num_grid_points,
145            actual: out.len(),
146        });
147    }
148
149    let expected_values = match representation {
150        DataRepresentation::SimplePacking(params) => params.encoded_values,
151        DataRepresentation::Grib1SecondOrderPacking(params) => params.packing().encoded_values,
152        DataRepresentation::ComplexPacking(params) => params.encoded_values,
153        DataRepresentation::IeeePacking(params) => params.encoded_values,
154        DataRepresentation::Jpeg2000Packing(params) => params.packing.encoded_values,
155        DataRepresentation::PngPacking(params) => params.packing.encoded_values,
156        DataRepresentation::CcsdsPacking(params) => params.packing().encoded_values,
157        DataRepresentation::RunLengthPacking(params) => params.encoded_values,
158        DataRepresentation::Unsupported(template) => {
159            return Err(Error::UnsupportedDataTemplate(*template));
160        }
161        _ => {
162            return Err(Error::InvalidMessage(
163                "data representation variant is not supported by this reader".into(),
164            ));
165        }
166    };
167    match bitmap_section {
168        Some(bitmap_payload) => {
169            let present_values = count_bitmap_present_points(bitmap_payload, num_grid_points)?;
170            if expected_values != present_values {
171                return Err(Error::DataLengthMismatch {
172                    expected: present_values,
173                    actual: expected_values,
174                });
175            }
176        }
177        None if expected_values != num_grid_points => {
178            return Err(Error::DataLengthMismatch {
179                expected: num_grid_points,
180                actual: expected_values,
181            });
182        }
183        None => {}
184    }
185
186    let mut output = OutputCursor::new(out, bitmap_section);
187    match representation {
188        DataRepresentation::SimplePacking(params) => {
189            unpack_simple_into(payload, params, expected_values, &mut output)?
190        }
191        DataRepresentation::Grib1SecondOrderPacking(params) => {
192            unpack_grib1_second_order_into(payload, params, row_group_lengths, &mut output)?
193        }
194        DataRepresentation::ComplexPacking(params) => {
195            unpack_complex_into(payload, params, row_group_lengths, &mut output)?
196        }
197        DataRepresentation::IeeePacking(params) => {
198            unpack_ieee_into(payload, params, expected_values, &mut output)?
199        }
200        DataRepresentation::Jpeg2000Packing(params) => {
201            unpack_jpeg2000_into(payload, params, expected_values, &mut output)?
202        }
203        DataRepresentation::PngPacking(params) => {
204            unpack_png_into(payload, params, expected_values, &mut output)?
205        }
206        DataRepresentation::CcsdsPacking(params) => {
207            unpack_ccsds_into(payload, params, expected_values, &mut output)?
208        }
209        DataRepresentation::RunLengthPacking(params) => {
210            unpack_run_length_into(payload, params, expected_values, &mut output)?
211        }
212        DataRepresentation::Unsupported(_) => unreachable!(),
213        _ => unreachable!("unsupported representation rejected before decoding"),
214    }
215    output.finish()
216}
217
218fn unpack_ieee_into<T: DecodeSample>(
219    data_bytes: &[u8],
220    params: &IeeePackingParams,
221    num_values: usize,
222    output: &mut OutputCursor<'_, T>,
223) -> Result<()> {
224    let expected_bytes = num_values
225        .checked_mul(params.precision.bytes_per_value())
226        .ok_or(Error::ArithmeticOverflow {
227            operation: "computing IEEE-packed byte count",
228        })?;
229    if data_bytes.len() != expected_bytes {
230        return Err(Error::DataLengthMismatch {
231            expected: expected_bytes,
232            actual: data_bytes.len(),
233        });
234    }
235
236    macro_rules! decode_values {
237        ($chunks:expr, $decode:expr) => {{
238            if let Some(dense) = output.take_dense(num_values)? {
239                for (target, bytes) in dense.iter_mut().zip($chunks) {
240                    *target = T::from_f64($decode(bytes));
241                }
242            } else {
243                for bytes in $chunks {
244                    output.push_present(T::from_f64($decode(bytes)))?;
245                }
246            }
247        }};
248    }
249
250    match params.precision {
251        IeeePrecision::Single => decode_values!(data_bytes.chunks_exact(4), |bytes: &[u8]| {
252            f64::from(f32::from_be_bytes(
253                bytes.try_into().expect("four-byte IEEE chunk"),
254            ))
255        }),
256        IeeePrecision::Double => decode_values!(data_bytes.chunks_exact(8), |bytes: &[u8]| {
257            f64::from_be_bytes(bytes.try_into().expect("eight-byte IEEE chunk"))
258        }),
259        IeeePrecision::Quadruple => {
260            decode_values!(data_bytes.chunks_exact(16), |bytes: &[u8]| {
261                decode_ieee_binary128(bytes.try_into().expect("sixteen-byte IEEE chunk"))
262            })
263        }
264        _ => {
265            return Err(Error::UnsupportedPackingWidth(
266                params.precision.bits_per_value(),
267            ));
268        }
269    }
270
271    Ok(())
272}
273
274fn unpack_run_length_into<T: DecodeSample>(
275    data_bytes: &[u8],
276    params: &RunLengthPackingParams,
277    num_values: usize,
278    output: &mut OutputCursor<'_, T>,
279) -> Result<()> {
280    if params.bits_per_value > 64 {
281        return Err(Error::InvalidSection {
282            section: 5,
283            reason: format!(
284                "template 5.200 bits per value must not exceed 64, got {}",
285                params.bits_per_value
286            ),
287        });
288    }
289    if params.max_level_value == 0 {
290        if !params.level_values.is_empty() {
291            return Err(Error::InvalidSection {
292                section: 5,
293                reason: format!(
294                    "template 5.200 zero maximum level requires an empty level table, got {} entries",
295                    params.level_values.len()
296                ),
297            });
298        }
299        if !remaining_bits_are_zero(data_bytes, 0)? {
300            return Err(invalid_run_length_data(
301                "all-missing field contains nonzero packed data",
302            ));
303        }
304        let missing = T::nan();
305        if let Some(dense) = output.take_dense(num_values)? {
306            dense.fill(missing);
307        } else {
308            for _ in 0..num_values {
309                output.push_present(missing)?;
310            }
311        }
312        return Ok(());
313    }
314
315    let bits = usize::from(params.bits_per_value);
316    if !(1..=64).contains(&bits) {
317        return Err(Error::InvalidSection {
318            section: 5,
319            reason: format!(
320                "template 5.200 bits per value must be between 1 and 64, got {}",
321                params.bits_per_value
322            ),
323        });
324    }
325    if usize::from(params.max_level_value) > params.level_values.len() {
326        return Err(Error::InvalidSection {
327            section: 5,
328            reason: format!(
329                "template 5.200 maximum level {} exceeds the {}-entry level table",
330                params.max_level_value,
331                params.level_values.len()
332            ),
333        });
334    }
335    let max_code = if bits == 64 {
336        u64::MAX
337    } else {
338        (1_u64 << bits) - 1
339    };
340    let range = max_code
341        .checked_sub(u64::from(params.max_level_value))
342        .filter(|range| *range > 0)
343        .ok_or_else(|| Error::InvalidSection {
344            section: 5,
345            reason: format!(
346                "template 5.200 maximum level {} leaves no run-length codes at {bits} bits",
347                params.max_level_value
348            ),
349        })?;
350    let data_bits = data_bytes
351        .len()
352        .checked_mul(8)
353        .ok_or(Error::BitOffsetOverflow)?;
354    let decimal_factor = 10.0_f64.powi(-i32::from(params.decimal_scale));
355    let mut reader = BitReader::new(data_bytes);
356    let mut decoded_values = 0usize;
357
358    while decoded_values < num_values {
359        if reader
360            .bit_offset()
361            .checked_add(bits)
362            .ok_or(Error::BitOffsetOverflow)?
363            > data_bits
364        {
365            return Err(Error::DataLengthMismatch {
366                expected: num_values,
367                actual: decoded_values,
368            });
369        }
370
371        let level = reader.read(bits)?;
372        if level > u64::from(params.max_level_value) {
373            return Err(invalid_run_length_data(format!(
374                "run starts with code {level}, above maximum level {}",
375                params.max_level_value
376            )));
377        }
378
379        let remaining_values = num_values - decoded_values;
380        let run_limit = remaining_values as u128;
381        let mut run_length = 1_u128;
382        let mut factor = 1_u128;
383        loop {
384            if reader
385                .bit_offset()
386                .checked_add(bits)
387                .ok_or(Error::BitOffsetOverflow)?
388                > data_bits
389            {
390                break;
391            }
392
393            let mut lookahead = reader;
394            let code = lookahead.read(bits)?;
395            if code <= u64::from(params.max_level_value) {
396                break;
397            }
398            reader = lookahead;
399
400            let digit = u128::from(code - u64::from(params.max_level_value) - 1);
401            let addition = factor.checked_mul(digit).ok_or(Error::ArithmeticOverflow {
402                operation: "decoding a template 5.200 run length",
403            })?;
404            run_length = run_length
405                .checked_add(addition)
406                .ok_or(Error::ArithmeticOverflow {
407                    operation: "decoding a template 5.200 run length",
408                })?;
409            if run_length > run_limit {
410                return Err(Error::DataLengthMismatch {
411                    expected: num_values,
412                    actual: num_values.saturating_add(1),
413                });
414            }
415            factor = factor.saturating_mul(u128::from(range)).min(run_limit + 1);
416        }
417
418        let run_length = usize::try_from(run_length).map_err(|_| Error::ArithmeticOverflow {
419            operation: "converting a template 5.200 run length",
420        })?;
421        let value = if level == 0 {
422            T::nan()
423        } else {
424            let scaled = params.level_values[usize::try_from(level - 1).map_err(|_| {
425                Error::ArithmeticOverflow {
426                    operation: "indexing a template 5.200 level",
427                }
428            })?];
429            T::from_f64(f64::from(scaled) * decimal_factor)
430        };
431        if let Some(dense) = output.take_dense(run_length)? {
432            dense.fill(value);
433        } else {
434            for _ in 0..run_length {
435                output.push_present(value)?;
436            }
437        }
438        decoded_values += run_length;
439    }
440
441    if !remaining_bits_are_zero(data_bytes, reader.bit_offset())? {
442        return Err(invalid_run_length_data(
443            "nonzero bits remain after the declared number of values",
444        ));
445    }
446    Ok(())
447}
448
449fn remaining_bits_are_zero(data: &[u8], start_bit: usize) -> Result<bool> {
450    let data_bits = data.len().checked_mul(8).ok_or(Error::BitOffsetOverflow)?;
451    if start_bit > data_bits {
452        return Err(Error::BitOffsetOverflow);
453    }
454    let mut byte_index = start_bit / 8;
455    let bit_index = start_bit % 8;
456    if bit_index != 0 {
457        let remaining_mask = u8::MAX >> bit_index;
458        if data[byte_index] & remaining_mask != 0 {
459            return Ok(false);
460        }
461        byte_index += 1;
462    }
463    Ok(data[byte_index..].iter().all(|byte| *byte == 0))
464}
465
466fn invalid_run_length_data(reason: impl Into<String>) -> Error {
467    Error::InvalidSection {
468        section: 7,
469        reason: format!("invalid template 5.200 data: {}", reason.into()),
470    }
471}
472
473/// Parse bitmap presence from Section 6.
474pub fn bitmap_payload(section_bytes: &[u8]) -> Result<Option<&[u8]>> {
475    if section_bytes.len() < 6 {
476        return Err(Error::InvalidSection {
477            section: 6,
478            reason: format!("expected at least 6 bytes, got {}", section_bytes.len()),
479        });
480    }
481    if section_bytes[4] != 6 {
482        return Err(Error::InvalidSection {
483            section: section_bytes[4],
484            reason: "not a bitmap section".into(),
485        });
486    }
487
488    match section_bytes[5] {
489        255 => Ok(None),
490        0 => Ok(Some(&section_bytes[6..])),
491        indicator => Err(Error::UnsupportedBitmapIndicator(u16::from(indicator))),
492    }
493}
494
495pub(crate) fn count_bitmap_present_points(
496    bitmap_payload: &[u8],
497    num_grid_points: usize,
498) -> Result<usize> {
499    let full_bytes = num_grid_points / 8;
500    let remaining_bits = num_grid_points % 8;
501    let required_bytes = full_bytes + usize::from(remaining_bits > 0);
502    if bitmap_payload.len() < required_bytes {
503        return Err(Error::DataLengthMismatch {
504            expected: required_bytes,
505            actual: bitmap_payload.len(),
506        });
507    }
508
509    let mut present = bitmap_payload[..full_bytes]
510        .iter()
511        .map(|byte| byte.count_ones() as usize)
512        .sum();
513    if remaining_bits > 0 {
514        let mask = u8::MAX << (8 - remaining_bits);
515        present += (bitmap_payload[full_bytes] & mask).count_ones() as usize;
516    }
517
518    Ok(present)
519}
520
521/// Unpack simple-packed values.
522pub fn unpack_simple(
523    data_bytes: &[u8],
524    params: &ScaledPackingParams,
525    num_values: usize,
526) -> Result<Vec<f64>> {
527    let mut values = filled_vec(num_values, 0.0, "simple-packed field")?;
528    let mut output = OutputCursor::new(&mut values, None);
529    unpack_simple_into(data_bytes, params, num_values, &mut output)?;
530    output.finish()?;
531    Ok(values)
532}
533
534fn unpack_simple_into<T: DecodeSample>(
535    data_bytes: &[u8],
536    params: &ScaledPackingParams,
537    num_values: usize,
538    output: &mut OutputCursor<'_, T>,
539) -> Result<()> {
540    let bits = params.bits_per_value as usize;
541    let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
542    let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
543    let reference = params.reference_value as f64;
544    if bits == 0 {
545        let constant = T::from_f64(scale_decoded_value(
546            reference,
547            0.0,
548            binary_factor,
549            decimal_factor,
550        ));
551        if let Some(dense) = output.take_dense(num_values)? {
552            dense.fill(constant);
553            return Ok(());
554        }
555        for _ in 0..num_values {
556            output.push_present(constant)?;
557        }
558        return Ok(());
559    }
560    if bits > u64::BITS as usize {
561        return Err(Error::UnsupportedPackingWidth(params.bits_per_value));
562    }
563
564    let required_bits = bits
565        .checked_mul(num_values)
566        .ok_or(Error::ArithmeticOverflow {
567            operation: "computing packed bit count",
568        })?;
569    let required_bytes = required_bits.div_ceil(8);
570    if data_bytes.len() < required_bytes {
571        return Err(Error::Truncated {
572            offset: data_bytes.len() as u64,
573        });
574    }
575
576    if let Some(dense) = output.take_dense(num_values)? {
577        return unpack_simple_dense(
578            data_bytes,
579            bits,
580            reference,
581            binary_factor,
582            decimal_factor,
583            dense,
584        );
585    }
586
587    let mut reader = BitReader::new(data_bytes);
588    for _ in 0..num_values {
589        let packed = reader.read(bits)?;
590        output.push_present(T::from_f64(scale_decoded_value(
591            reference,
592            packed as f64,
593            binary_factor,
594            decimal_factor,
595        )))?;
596    }
597
598    Ok(())
599}
600
601fn unpack_simple_dense<T: DecodeSample>(
602    data_bytes: &[u8],
603    bits: usize,
604    reference: f64,
605    binary_factor: f64,
606    decimal_factor: f64,
607    output: &mut [T],
608) -> Result<()> {
609    let scale = |packed: u64| {
610        T::from_f64(scale_decoded_value(
611            reference,
612            packed as f64,
613            binary_factor,
614            decimal_factor,
615        ))
616    };
617
618    match bits {
619        8 => {
620            for (target, &packed) in output.iter_mut().zip(data_bytes) {
621                *target = scale(u64::from(packed));
622            }
623        }
624        16 => {
625            for (target, bytes) in output.iter_mut().zip(data_bytes.chunks_exact(2)) {
626                *target = scale(u64::from(u16::from_be_bytes(
627                    bytes.try_into().expect("two-byte chunk"),
628                )));
629            }
630        }
631        32 => {
632            for (target, bytes) in output.iter_mut().zip(data_bytes.chunks_exact(4)) {
633                *target = scale(u64::from(u32::from_be_bytes(
634                    bytes.try_into().expect("four-byte chunk"),
635                )));
636            }
637        }
638        64 => {
639            for (target, bytes) in output.iter_mut().zip(data_bytes.chunks_exact(8)) {
640                *target = scale(u64::from_be_bytes(
641                    bytes.try_into().expect("eight-byte chunk"),
642                ));
643            }
644        }
645        _ => {
646            let mut reader = BitReader::new(data_bytes);
647            for target in output {
648                *target = scale(reader.read(bits)?);
649            }
650        }
651    }
652    Ok(())
653}
654
655#[cfg(feature = "ccsds")]
656fn unpack_ccsds_into<T: DecodeSample>(
657    data_bytes: &[u8],
658    params: &CcsdsPackingParams,
659    num_values: usize,
660    output: &mut OutputCursor<'_, T>,
661) -> Result<()> {
662    let packing = params.packing();
663    let bits = packing.bits_per_value;
664
665    if bits == 0 {
666        if !data_bytes.is_empty() {
667            return Err(Error::DataLengthMismatch {
668                expected: 0,
669                actual: data_bytes.len(),
670            });
671        }
672        // ecCodes stores a constant CCSDS field directly in referenceValue and
673        // ignores both scale factors when bitsPerValue is zero.
674        let value = T::from_f64(f64::from(packing.reference_value));
675        if let Some(dense) = output.take_dense(num_values)? {
676            dense.fill(value);
677        } else {
678            for _ in 0..num_values {
679                output.push_present(value)?;
680            }
681        }
682        return Ok(());
683    }
684
685    if num_values == 0 {
686        if data_bytes.is_empty() {
687            return Ok(());
688        }
689        return Err(Error::DataLengthMismatch {
690            expected: 0,
691            actual: data_bytes.len(),
692        });
693    }
694
695    let bytes_per_sample = usize::from(bits).div_ceil(8);
696    let decoded_size =
697        num_values
698            .checked_mul(bytes_per_sample)
699            .ok_or(Error::ArithmeticOverflow {
700                operation: "computing CCSDS decoded byte count",
701            })?;
702    let codec_params = AecParams::new(
703        bits,
704        params.block_size().samples(),
705        params.reference_sample_interval(),
706        ccsds_decoder_flags(params.flags()),
707    )
708    .map_err(|error| Error::Codec {
709        codec: "CCSDS/AEC",
710        operation: "configure",
711        reason: error.to_string(),
712    })?;
713    let decoded =
714        aec_decode(data_bytes, num_values, codec_params).map_err(|error| Error::Codec {
715            codec: "CCSDS/AEC",
716            operation: "decode",
717            reason: error.to_string(),
718        })?;
719    if decoded.len() != decoded_size {
720        return Err(Error::DataLengthMismatch {
721            expected: decoded_size,
722            actual: decoded.len(),
723        });
724    }
725
726    let value_mask = if bits == 32 {
727        u32::MAX
728    } else {
729        (1u32 << bits) - 1
730    };
731    for bytes in decoded.chunks_exact(bytes_per_sample) {
732        let container = bytes
733            .iter()
734            .fold(0u32, |value, byte| (value << 8) | u32::from(*byte));
735        let raw = container & value_mask;
736        let signed = params.flags().contains(CcsdsFlags::SIGNED);
737        let high_mask = if bytes_per_sample == 4 {
738            !value_mask
739        } else {
740            ((1u32 << (bytes_per_sample * 8)) - 1) & !value_mask
741        };
742        let expected_high = if signed && raw & (1u32 << (bits - 1)) != 0 {
743            high_mask
744        } else {
745            0
746        };
747        if container & high_mask != expected_high {
748            return Err(Error::ValueOutOfRange(format!(
749                "CCSDS sample container 0x{container:08x} has invalid extension bits for its {bits}-bit width"
750            )));
751        }
752        // SIGNED controls the AEC preprocessor. GRIB template 5.42 still
753        // stores non-negative scaled differences, so reconstruction uses the
754        // declared low bits as an unsigned value.
755        output.push_present(scale_ccsds_value(packing, f64::from(raw)))?;
756    }
757    Ok(())
758}
759
760#[cfg(feature = "ccsds")]
761fn ccsds_decoder_flags(flags: CcsdsFlags) -> AecFlags {
762    // MSB and THREE_BYTE describe the caller's decoded sample containers, not
763    // the CCSDS bitstream. Request one canonical, compact big-endian layout so
764    // the reader never depends on host endianness or four-byte padding.
765    let mut codec_flags = AecFlags::DATA_MSB | AecFlags::DATA_3BYTE;
766    for (wire_flag, codec_flag) in [
767        (CcsdsFlags::SIGNED, AecFlags::DATA_SIGNED),
768        (CcsdsFlags::PREPROCESS, AecFlags::DATA_PREPROCESS),
769        (CcsdsFlags::RESTRICTED, AecFlags::RESTRICTED),
770        (CcsdsFlags::PAD_RSI, AecFlags::PAD_RSI),
771        (CcsdsFlags::NOT_ENFORCE, AecFlags::NOT_ENFORCE),
772    ] {
773        if flags.contains(wire_flag) {
774            codec_flags |= codec_flag;
775        }
776    }
777    codec_flags
778}
779
780#[cfg(feature = "ccsds")]
781fn scale_ccsds_value<T: DecodeSample>(params: &ScaledPackingParams, packed: f64) -> T {
782    T::from_f64(scale_decoded_value(
783        f64::from(params.reference_value),
784        packed,
785        2.0_f64.powi(i32::from(params.binary_scale)),
786        10.0_f64.powi(-i32::from(params.decimal_scale)),
787    ))
788}
789
790#[cfg(not(feature = "ccsds"))]
791fn unpack_ccsds_into<T: DecodeSample>(
792    _data_bytes: &[u8],
793    _params: &CcsdsPackingParams,
794    _num_values: usize,
795    _output: &mut OutputCursor<'_, T>,
796) -> Result<()> {
797    Err(Error::UnsupportedDataTemplate(42))
798}
799
800#[cfg(feature = "jpeg2000")]
801fn unpack_jpeg2000_into<T: DecodeSample>(
802    data_bytes: &[u8],
803    params: &Jpeg2000PackingParams,
804    num_values: usize,
805    output: &mut OutputCursor<'_, T>,
806) -> Result<()> {
807    validate_jpeg2000_bits(params.packing.bits_per_value)?;
808
809    // Parse the SIZ marker in safe Rust before OpenJPEG allocates or decodes
810    // sample data. jpeg2k's header-only DumpImage path currently frees a null
811    // OpenJPEG code-block pointer on some valid codestreams, so it cannot be
812    // used as the validation boundary.
813    let header = parse_jpeg2000_header(data_bytes)?;
814    if header.components != 1 {
815        return Err(invalid_data_section(format!(
816            "JPEG 2000 GRIB packing requires one component, got {}",
817            header.components
818        )));
819    }
820    if header.is_signed {
821        return Err(invalid_data_section(
822            "JPEG 2000 GRIB packing requires unsigned component data",
823        ));
824    }
825    if header.precision > params.packing.bits_per_value {
826        return Err(invalid_data_section(format!(
827            "JPEG 2000 component precision {} exceeds GRIB bits-per-value {}",
828            header.precision, params.packing.bits_per_value
829        )));
830    }
831
832    let sample_count = image_sample_count(header.width, header.height)?;
833    if sample_count != num_values {
834        return Err(Error::DataLengthMismatch {
835            expected: num_values,
836            actual: sample_count,
837        });
838    }
839
840    let image = jpeg2k::Image::from_bytes(data_bytes).map_err(|err| Error::Codec {
841        codec: "JPEG 2000",
842        operation: "decode",
843        reason: err.to_string(),
844    })?;
845    if image.num_components() != 1 {
846        return Err(invalid_data_section(format!(
847            "JPEG 2000 GRIB packing requires one component, got {}",
848            image.num_components()
849        )));
850    }
851    let component = image
852        .components()
853        .first()
854        .ok_or_else(|| invalid_data_section("JPEG 2000 image has no components"))?;
855    if component.is_signed() {
856        return Err(invalid_data_section(
857            "JPEG 2000 GRIB packing requires unsigned component data",
858        ));
859    }
860    if component.precision() > u32::from(params.packing.bits_per_value) {
861        return Err(invalid_data_section(format!(
862            "JPEG 2000 component precision {} exceeds GRIB bits-per-value {}",
863            component.precision(),
864            params.packing.bits_per_value
865        )));
866    }
867    let decoded_sample_count = image_sample_count(component.width(), component.height())?;
868    if decoded_sample_count != num_values {
869        return Err(Error::DataLengthMismatch {
870            expected: num_values,
871            actual: decoded_sample_count,
872        });
873    }
874
875    for &sample in component.data() {
876        let raw = jpeg2000_raw_value(sample, params.packing.bits_per_value)?;
877        push_image_value(output, &params.packing, raw)?;
878    }
879
880    Ok(())
881}
882
883#[cfg(feature = "jpeg2000")]
884#[derive(Debug, Clone, Copy, PartialEq, Eq)]
885struct Jpeg2000Header {
886    width: u32,
887    height: u32,
888    components: u16,
889    precision: u8,
890    is_signed: bool,
891}
892
893#[cfg(feature = "jpeg2000")]
894fn parse_jpeg2000_header(data: &[u8]) -> Result<Jpeg2000Header> {
895    let codestream = jpeg2000_codestream(data)?;
896    if codestream.get(..4) != Some(&[0xff, 0x4f, 0xff, 0x51]) {
897        return Err(invalid_jpeg2000_header(
898            "codestream does not begin with SOC followed by SIZ",
899        ));
900    }
901
902    let segment_length = usize::from(u16::from_be_bytes(codestream[4..6].try_into().unwrap()));
903    let segment_end = 4usize
904        .checked_add(segment_length)
905        .ok_or_else(|| invalid_jpeg2000_header("SIZ segment length overflow"))?;
906    let segment = codestream
907        .get(4..segment_end)
908        .ok_or_else(|| invalid_jpeg2000_header("truncated SIZ segment"))?;
909    if segment.len() < 38 {
910        return Err(invalid_jpeg2000_header("SIZ segment is too short"));
911    }
912
913    let components = u16::from_be_bytes(segment[36..38].try_into().unwrap());
914    let required_length = usize::from(components)
915        .checked_mul(3)
916        .and_then(|component_bytes| 38usize.checked_add(component_bytes))
917        .ok_or_else(|| invalid_jpeg2000_header("SIZ component table length overflow"))?;
918    if segment_length != required_length {
919        return Err(invalid_jpeg2000_header(format!(
920            "SIZ length {segment_length} does not match {components} components"
921        )));
922    }
923    if components == 0 {
924        return Err(invalid_jpeg2000_header("SIZ declares zero components"));
925    }
926
927    let xsiz = u32::from_be_bytes(segment[4..8].try_into().unwrap());
928    let ysiz = u32::from_be_bytes(segment[8..12].try_into().unwrap());
929    let xosiz = u32::from_be_bytes(segment[12..16].try_into().unwrap());
930    let yosiz = u32::from_be_bytes(segment[16..20].try_into().unwrap());
931    let xrsiz = u32::from(segment[39]);
932    let yrsiz = u32::from(segment[40]);
933    if xrsiz == 0 || yrsiz == 0 {
934        return Err(invalid_jpeg2000_header(
935            "SIZ component subsampling factors must be nonzero",
936        ));
937    }
938    let width = ceil_div_u32(xsiz, xrsiz)
939        .checked_sub(ceil_div_u32(xosiz, xrsiz))
940        .filter(|width| *width > 0)
941        .ok_or_else(|| invalid_jpeg2000_header("SIZ has an invalid horizontal extent"))?;
942    let height = ceil_div_u32(ysiz, yrsiz)
943        .checked_sub(ceil_div_u32(yosiz, yrsiz))
944        .filter(|height| *height > 0)
945        .ok_or_else(|| invalid_jpeg2000_header("SIZ has an invalid vertical extent"))?;
946    let sample_format = segment[38];
947
948    Ok(Jpeg2000Header {
949        width,
950        height,
951        components,
952        precision: (sample_format & 0x7f) + 1,
953        is_signed: sample_format & 0x80 != 0,
954    })
955}
956
957#[cfg(feature = "jpeg2000")]
958fn jpeg2000_codestream(data: &[u8]) -> Result<&[u8]> {
959    if data.starts_with(&[0xff, 0x4f]) {
960        return Ok(data);
961    }
962
963    let mut offset = 0usize;
964    while offset
965        .checked_add(8)
966        .is_some_and(|header_end| header_end <= data.len())
967    {
968        let short_length = u32::from_be_bytes(data[offset..offset + 4].try_into().unwrap());
969        let box_type = &data[offset + 4..offset + 8];
970        let (header_length, box_length) = match short_length {
971            0 => (8usize, data.len() - offset),
972            1 => {
973                let extended_end = offset
974                    .checked_add(16)
975                    .ok_or_else(|| invalid_jpeg2000_header("JP2 box header overflow"))?;
976                let extended = data
977                    .get(offset + 8..extended_end)
978                    .ok_or_else(|| invalid_jpeg2000_header("truncated extended JP2 box"))?;
979                let length = usize::try_from(u64::from_be_bytes(extended.try_into().unwrap()))
980                    .map_err(|_| invalid_jpeg2000_header("JP2 box length exceeds usize"))?;
981                (16usize, length)
982            }
983            length => (8usize, length as usize),
984        };
985        if box_length < header_length {
986            return Err(invalid_jpeg2000_header(
987                "JP2 box is shorter than its header",
988            ));
989        }
990        let box_end = offset
991            .checked_add(box_length)
992            .filter(|end| *end <= data.len())
993            .ok_or_else(|| invalid_jpeg2000_header("JP2 box extends past the payload"))?;
994        if box_type == b"jp2c" {
995            return data
996                .get(offset + header_length..box_end)
997                .ok_or_else(|| invalid_jpeg2000_header("truncated JP2 codestream box"));
998        }
999        if short_length == 0 {
1000            break;
1001        }
1002        offset = box_end;
1003    }
1004
1005    Err(invalid_jpeg2000_header(
1006        "payload is neither a raw codestream nor a JP2 file with a codestream box",
1007    ))
1008}
1009
1010#[cfg(feature = "jpeg2000")]
1011const fn ceil_div_u32(value: u32, divisor: u32) -> u32 {
1012    value / divisor + (!value.is_multiple_of(divisor)) as u32
1013}
1014
1015#[cfg(feature = "jpeg2000")]
1016fn invalid_jpeg2000_header(reason: impl Into<String>) -> Error {
1017    invalid_data_section(format!("invalid JPEG 2000 header: {}", reason.into()))
1018}
1019
1020#[cfg(any(feature = "jpeg2000", feature = "png"))]
1021fn invalid_data_section(reason: impl Into<String>) -> Error {
1022    Error::InvalidSection {
1023        section: 7,
1024        reason: reason.into(),
1025    }
1026}
1027
1028#[cfg(not(feature = "jpeg2000"))]
1029fn unpack_jpeg2000_into<T: DecodeSample>(
1030    _data_bytes: &[u8],
1031    _params: &Jpeg2000PackingParams,
1032    _num_values: usize,
1033    _output: &mut OutputCursor<'_, T>,
1034) -> Result<()> {
1035    Err(Error::UnsupportedDataTemplate(40))
1036}
1037
1038#[cfg(feature = "jpeg2000")]
1039fn validate_jpeg2000_bits(bits_per_value: u8) -> Result<()> {
1040    if !(1..=32).contains(&bits_per_value) {
1041        return Err(Error::UnsupportedPackingWidth(bits_per_value));
1042    }
1043    Ok(())
1044}
1045
1046#[cfg(feature = "jpeg2000")]
1047fn jpeg2000_raw_value(sample: i32, bits_per_value: u8) -> Result<u64> {
1048    let raw = if bits_per_value == 32 {
1049        u64::from(u32::from_ne_bytes(sample.to_ne_bytes()))
1050    } else {
1051        u64::try_from(sample).map_err(|_| {
1052            Error::ValueOutOfRange("JPEG 2000 unsigned component yielded a negative sample".into())
1053        })?
1054    };
1055    validate_raw_value_fits(raw, bits_per_value)?;
1056    Ok(raw)
1057}
1058
1059#[cfg(feature = "png")]
1060fn unpack_png_into<T: DecodeSample>(
1061    data_bytes: &[u8],
1062    params: &PngPackingParams,
1063    num_values: usize,
1064    output: &mut OutputCursor<'_, T>,
1065) -> Result<()> {
1066    validate_png_bits(params.packing.bits_per_value)?;
1067
1068    let decoder = png::Decoder::new(std::io::Cursor::new(data_bytes));
1069    let mut reader = decoder.read_info().map_err(|err| Error::Codec {
1070        codec: "PNG",
1071        operation: "read header",
1072        reason: err.to_string(),
1073    })?;
1074    let header_sample_count = image_sample_count(reader.info().width, reader.info().height)?;
1075    if header_sample_count != num_values {
1076        return Err(Error::DataLengthMismatch {
1077            expected: num_values,
1078            actual: header_sample_count,
1079        });
1080    }
1081    let buffer_size = reader
1082        .output_buffer_size()
1083        .ok_or(Error::ArithmeticOverflow {
1084            operation: "computing PNG output buffer size",
1085        })?;
1086    let mut buffer = filled_vec(buffer_size, 0, "PNG output buffer")?;
1087    let info = reader.next_frame(&mut buffer).map_err(|err| Error::Codec {
1088        codec: "PNG",
1089        operation: "decode",
1090        reason: err.to_string(),
1091    })?;
1092    let data = &buffer[..info.buffer_size()];
1093
1094    let sample_count = image_sample_count(info.width, info.height)?;
1095    if sample_count != num_values {
1096        return Err(Error::DataLengthMismatch {
1097            expected: num_values,
1098            actual: sample_count,
1099        });
1100    }
1101
1102    match (
1103        info.color_type,
1104        info.bit_depth,
1105        params.packing.bits_per_value,
1106    ) {
1107        (png::ColorType::Grayscale, png::BitDepth::One, 1)
1108        | (png::ColorType::Grayscale, png::BitDepth::Two, 2)
1109        | (png::ColorType::Grayscale, png::BitDepth::Four, 4) => unpack_png_subbyte_grayscale(
1110            data,
1111            info.width,
1112            info.height,
1113            params.packing.bits_per_value,
1114            &params.packing,
1115            output,
1116        ),
1117        (png::ColorType::Grayscale, png::BitDepth::Eight, 8) => {
1118            unpack_png_bytes(data, 1, num_values, &params.packing, output)
1119        }
1120        (png::ColorType::Grayscale, png::BitDepth::Sixteen, 16) => {
1121            unpack_png_u16(data, num_values, &params.packing, output)
1122        }
1123        (png::ColorType::Rgb, png::BitDepth::Eight, 24) => {
1124            unpack_png_bytes(data, 3, num_values, &params.packing, output)
1125        }
1126        (png::ColorType::Rgba, png::BitDepth::Eight, 32) => {
1127            unpack_png_bytes(data, 4, num_values, &params.packing, output)
1128        }
1129        (color_type, bit_depth, bits_per_value) => Err(invalid_data_section(format!(
1130            "PNG image layout {color_type:?}/{bit_depth:?} is incompatible with GRIB bits-per-value {bits_per_value}"
1131        ))),
1132    }
1133}
1134
1135#[cfg(not(feature = "png"))]
1136fn unpack_png_into<T: DecodeSample>(
1137    _data_bytes: &[u8],
1138    _params: &PngPackingParams,
1139    _num_values: usize,
1140    _output: &mut OutputCursor<'_, T>,
1141) -> Result<()> {
1142    Err(Error::UnsupportedDataTemplate(41))
1143}
1144
1145#[cfg(feature = "png")]
1146fn validate_png_bits(bits_per_value: u8) -> Result<()> {
1147    if !matches!(bits_per_value, 1 | 2 | 4 | 8 | 16 | 24 | 32) {
1148        return Err(Error::UnsupportedPackingWidth(bits_per_value));
1149    }
1150    Ok(())
1151}
1152
1153#[cfg(any(feature = "jpeg2000", feature = "png"))]
1154fn image_sample_count(width: u32, height: u32) -> Result<usize> {
1155    let width = usize::try_from(width)
1156        .map_err(|_| Error::ValueOutOfRange("image width exceeds usize".into()))?;
1157    let height = usize::try_from(height)
1158        .map_err(|_| Error::ValueOutOfRange("image height exceeds usize".into()))?;
1159    width.checked_mul(height).ok_or(Error::ArithmeticOverflow {
1160        operation: "computing image sample count",
1161    })
1162}
1163
1164#[cfg(feature = "png")]
1165fn unpack_png_subbyte_grayscale<T: DecodeSample>(
1166    data: &[u8],
1167    width: u32,
1168    height: u32,
1169    bits_per_sample: u8,
1170    params: &ScaledPackingParams,
1171    output: &mut OutputCursor<'_, T>,
1172) -> Result<()> {
1173    let width = usize::try_from(width)
1174        .map_err(|_| Error::ValueOutOfRange("PNG width exceeds usize".into()))?;
1175    let height = usize::try_from(height)
1176        .map_err(|_| Error::ValueOutOfRange("PNG height exceeds usize".into()))?;
1177    let bits = usize::from(bits_per_sample);
1178    let row_bytes = width
1179        .checked_mul(bits)
1180        .ok_or(Error::ArithmeticOverflow {
1181            operation: "computing PNG row width",
1182        })?
1183        .div_ceil(8);
1184    let expected_bytes = row_bytes
1185        .checked_mul(height)
1186        .ok_or(Error::ArithmeticOverflow {
1187            operation: "computing PNG data length",
1188        })?;
1189    if data.len() < expected_bytes {
1190        return Err(Error::DataLengthMismatch {
1191            expected: expected_bytes,
1192            actual: data.len(),
1193        });
1194    }
1195
1196    let mask = (1u8 << bits) - 1;
1197    for row in data[..expected_bytes].chunks_exact(row_bytes) {
1198        for x in 0..width {
1199            let bit_offset = x.checked_mul(bits).ok_or(Error::BitOffsetOverflow)?;
1200            let shift = 8 - bits - (bit_offset % 8);
1201            let raw = u64::from((row[bit_offset / 8] >> shift) & mask);
1202            push_image_value(output, params, raw)?;
1203        }
1204    }
1205
1206    Ok(())
1207}
1208
1209#[cfg(feature = "png")]
1210fn unpack_png_bytes<T: DecodeSample>(
1211    data: &[u8],
1212    bytes_per_sample: usize,
1213    num_values: usize,
1214    params: &ScaledPackingParams,
1215    output: &mut OutputCursor<'_, T>,
1216) -> Result<()> {
1217    let expected_bytes =
1218        num_values
1219            .checked_mul(bytes_per_sample)
1220            .ok_or(Error::ArithmeticOverflow {
1221                operation: "computing PNG data length",
1222            })?;
1223    if data.len() < expected_bytes {
1224        return Err(Error::DataLengthMismatch {
1225            expected: expected_bytes,
1226            actual: data.len(),
1227        });
1228    }
1229
1230    for sample in data[..expected_bytes].chunks_exact(bytes_per_sample) {
1231        let raw = sample
1232            .iter()
1233            .fold(0u64, |acc, byte| (acc << 8) | u64::from(*byte));
1234        push_image_value(output, params, raw)?;
1235    }
1236
1237    Ok(())
1238}
1239
1240#[cfg(feature = "png")]
1241fn unpack_png_u16<T: DecodeSample>(
1242    data: &[u8],
1243    num_values: usize,
1244    params: &ScaledPackingParams,
1245    output: &mut OutputCursor<'_, T>,
1246) -> Result<()> {
1247    let expected_bytes = num_values.checked_mul(2).ok_or(Error::ArithmeticOverflow {
1248        operation: "computing PNG data length",
1249    })?;
1250    if data.len() < expected_bytes {
1251        return Err(Error::DataLengthMismatch {
1252            expected: expected_bytes,
1253            actual: data.len(),
1254        });
1255    }
1256
1257    for sample in data[..expected_bytes].chunks_exact(2) {
1258        let raw = u64::from(u16::from_be_bytes(sample.try_into().unwrap()));
1259        push_image_value(output, params, raw)?;
1260    }
1261
1262    Ok(())
1263}
1264
1265#[cfg(any(feature = "jpeg2000", feature = "png"))]
1266fn push_image_value<T: DecodeSample>(
1267    output: &mut OutputCursor<'_, T>,
1268    params: &ScaledPackingParams,
1269    raw: u64,
1270) -> Result<()> {
1271    validate_raw_value_fits(raw, params.bits_per_value)?;
1272    output.push_present(scale_image_value(params, raw))
1273}
1274
1275#[cfg(any(feature = "jpeg2000", feature = "png"))]
1276fn validate_raw_value_fits(raw: u64, bits_per_value: u8) -> Result<()> {
1277    let max_value = if bits_per_value == u64::BITS as u8 {
1278        u64::MAX
1279    } else {
1280        (1u64 << bits_per_value) - 1
1281    };
1282    if raw > max_value {
1283        return Err(Error::ValueOutOfRange(format!(
1284            "decoded image sample {raw} exceeds GRIB bits-per-value {bits_per_value}"
1285        )));
1286    }
1287    Ok(())
1288}
1289
1290#[cfg(any(feature = "jpeg2000", feature = "png"))]
1291fn scale_image_value<T: DecodeSample>(params: &ScaledPackingParams, raw: u64) -> T {
1292    let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
1293    let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
1294    T::from_f64(scale_decoded_value(
1295        params.reference_value as f64,
1296        raw as f64,
1297        binary_factor,
1298        decimal_factor,
1299    ))
1300}
1301
1302#[cfg(test)]
1303fn unpack_complex(data_bytes: &[u8], params: &ComplexPackingParams) -> Result<Vec<f64>> {
1304    let mut values = filled_vec(params.encoded_values, 0.0, "complex-packed field")?;
1305    let mut output = OutputCursor::new(&mut values, None);
1306    unpack_complex_into(data_bytes, params, None, &mut output)?;
1307    output.finish()?;
1308    Ok(values)
1309}
1310
1311fn unpack_grib1_second_order_into<T: DecodeSample>(
1312    data_bytes: &[u8],
1313    params: &Grib1SecondOrderPackingParams,
1314    row_group_lengths: Option<&[usize]>,
1315    output: &mut OutputCursor<'_, T>,
1316) -> Result<()> {
1317    let group_lengths = match params.layout() {
1318        Grib1SecondOrderLayout::RowByRow => {
1319            row_group_lengths.ok_or_else(|| Error::InvalidSection {
1320                section: 4,
1321                reason: "GRIB1 row-by-row second-order packing requires grid-derived group lengths"
1322                    .into(),
1323            })?
1324        }
1325        Grib1SecondOrderLayout::ConstantWidth | Grib1SecondOrderLayout::VariableWidth => {
1326            params.group_lengths()
1327        }
1328        _ => {
1329            return Err(Error::InvalidSection {
1330                section: 4,
1331                reason: "unsupported GRIB1 second-order group layout".into(),
1332            });
1333        }
1334    };
1335    validate_external_group_lengths(
1336        group_lengths,
1337        params.group_count(),
1338        params.packing().encoded_values,
1339        "GRIB1 second-order",
1340        4,
1341    )?;
1342
1343    let first_order_offset = params
1344        .first_order_values_offset()
1345        .checked_mul(8)
1346        .ok_or(Error::BitOffsetOverflow)?;
1347    let second_order_offset = params
1348        .second_order_values_offset()
1349        .checked_mul(8)
1350        .ok_or(Error::BitOffsetOverflow)?;
1351    let mut first_order_reader = BitReader::with_offset(data_bytes, first_order_offset);
1352    let mut second_order_reader = BitReader::with_offset(data_bytes, second_order_offset);
1353    let packing = params.packing();
1354    let binary_factor = 2.0_f64.powi(i32::from(packing.binary_scale));
1355    let decimal_factor = 10.0_f64.powi(-i32::from(packing.decimal_scale));
1356    let reference = f64::from(packing.reference_value);
1357
1358    for (group_index, group_length) in group_lengths.iter().copied().enumerate() {
1359        let first_order = first_order_reader.read(usize::from(packing.bits_per_value))?;
1360        let group_width = params
1361            .group_width(group_index)
1362            .ok_or_else(|| Error::InvalidSection {
1363                section: 4,
1364                reason: format!("missing width for GRIB1 second-order group {group_index}"),
1365            })?;
1366        for _ in 0..group_length {
1367            let second_order = second_order_reader.read(usize::from(group_width))?;
1368            let packed =
1369                first_order
1370                    .checked_add(second_order)
1371                    .ok_or(Error::ArithmeticOverflow {
1372                        operation: "reconstructing a GRIB1 second-order value",
1373                    })?;
1374            output.push_present(T::from_f64(scale_decoded_value(
1375                reference,
1376                packed as f64,
1377                binary_factor,
1378                decimal_factor,
1379            )))?;
1380        }
1381    }
1382
1383    let payload_bits = data_bytes
1384        .len()
1385        .checked_mul(8)
1386        .ok_or(Error::BitOffsetOverflow)?;
1387    let usable_bits = payload_bits
1388        .checked_sub(usize::from(params.unused_bits()))
1389        .ok_or_else(|| Error::InvalidSection {
1390            section: 4,
1391            reason: "GRIB1 BDS unused-bit count exceeds its payload".into(),
1392        })?;
1393    if second_order_reader.bit_offset() != usable_bits {
1394        return Err(Error::InvalidSection {
1395            section: 4,
1396            reason: format!(
1397                "GRIB1 second-order values end at bit {}, expected {usable_bits}",
1398                second_order_reader.bit_offset()
1399            ),
1400        });
1401    }
1402    if output.values_written() != packing.encoded_values {
1403        return Err(Error::DataLengthMismatch {
1404            expected: packing.encoded_values,
1405            actual: output.values_written(),
1406        });
1407    }
1408    Ok(())
1409}
1410
1411fn unpack_complex_into<T: DecodeSample>(
1412    data_bytes: &[u8],
1413    params: &ComplexPackingParams,
1414    row_group_lengths: Option<&[usize]>,
1415    output: &mut OutputCursor<'_, T>,
1416) -> Result<()> {
1417    if params.num_groups == 0 {
1418        return Err(Error::InvalidSection {
1419            section: 5,
1420            reason: "complex packing requires at least one group".into(),
1421        });
1422    }
1423
1424    let mut reader = BitReader::new(data_bytes);
1425    let mut spatial = params
1426        .spatial_differencing
1427        .map(|spatial| read_spatial_descriptors(&mut reader, spatial))
1428        .transpose()?
1429        .map(SpatialRestoreState::new);
1430
1431    let layout = GroupReaderLayout::new(reader.bit_offset(), params)?;
1432    let mut reference_reader = BitReader::with_offset(data_bytes, layout.reference_offset);
1433    let mut width_reader = BitReader::with_offset(data_bytes, layout.width_offset);
1434    let mut length_reader = BitReader::with_offset(data_bytes, layout.length_offset);
1435    let mut value_reader = BitReader::with_offset(data_bytes, layout.value_offset);
1436    let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
1437    let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
1438    let reference = params.reference_value as f64;
1439    let mut actual_total = 0usize;
1440    let row_group_lengths = match params.group_splitting_method {
1441        0 => {
1442            let lengths = row_group_lengths.ok_or_else(|| Error::InvalidSection {
1443                section: 5,
1444                reason:
1445                    "complex packing group splitting method 0 requires grid-derived group lengths"
1446                        .into(),
1447            })?;
1448            validate_external_group_lengths(
1449                lengths,
1450                params.num_groups,
1451                params.encoded_values,
1452                "complex-packing row",
1453                5,
1454            )?;
1455            Some(lengths)
1456        }
1457        1 => None,
1458        method => return Err(Error::UnsupportedGroupSplittingMethod(method)),
1459    };
1460
1461    for group_index in 0..params.num_groups {
1462        let group_reference = reference_reader.read(params.group_reference_bits as usize)?;
1463        let width_delta = width_reader.read(params.group_width_bits as usize)?;
1464        let group_width = usize::from(params.group_width_reference)
1465            .checked_add(width_delta as usize)
1466            .ok_or(Error::ArithmeticOverflow {
1467                operation: "computing complex-packing group width",
1468            })?;
1469        let group_length = match row_group_lengths {
1470            Some(lengths) => lengths[group_index],
1471            None => read_group_length(&mut length_reader, params, group_index)?,
1472        };
1473
1474        actual_total = actual_total
1475            .checked_add(group_length)
1476            .ok_or(Error::ArithmeticOverflow {
1477                operation: "summing complex-packing group lengths",
1478            })?;
1479
1480        if group_width == 0 {
1481            let raw_value = decode_constant_group_value(
1482                group_reference,
1483                params.group_reference_bits as usize,
1484                params.missing_value_management,
1485            )?;
1486            for _ in 0..group_length {
1487                let value = spatial
1488                    .as_mut()
1489                    .map_or(Ok(raw_value), |state| state.restore(raw_value))?;
1490                output.push_present(scale_complex_value(
1491                    reference,
1492                    binary_factor,
1493                    decimal_factor,
1494                    value,
1495                ))?;
1496            }
1497            continue;
1498        }
1499
1500        if group_width > u64::BITS as usize {
1501            return Err(Error::UnsupportedPackingWidth(group_width as u8));
1502        }
1503
1504        let group_reference = i64::try_from(group_reference)
1505            .map_err(|_| Error::ValueOutOfRange("group reference exceeds i64".into()))?;
1506        for _ in 0..group_length {
1507            let packed = value_reader.read(group_width)?;
1508            let value = decode_group_value(
1509                group_reference,
1510                packed,
1511                group_width,
1512                params.missing_value_management,
1513            )?;
1514            let value = spatial
1515                .as_mut()
1516                .map_or(Ok(value), |state| state.restore(value))?;
1517            output.push_present(scale_complex_value(
1518                reference,
1519                binary_factor,
1520                decimal_factor,
1521                value,
1522            ))?;
1523        }
1524    }
1525
1526    if actual_total != params.encoded_values {
1527        return Err(Error::DataLengthMismatch {
1528            expected: params.encoded_values,
1529            actual: actual_total,
1530        });
1531    }
1532
1533    if output.values_written() != params.encoded_values {
1534        return Err(Error::DataLengthMismatch {
1535            expected: params.encoded_values,
1536            actual: output.values_written(),
1537        });
1538    }
1539
1540    if let Some(spatial) = spatial {
1541        spatial.finish()?;
1542    }
1543
1544    Ok(())
1545}
1546
1547fn validate_external_group_lengths(
1548    lengths: &[usize],
1549    expected_groups: usize,
1550    expected_values: usize,
1551    packing_name: &str,
1552    section: u8,
1553) -> Result<()> {
1554    if lengths.len() != expected_groups {
1555        return Err(Error::InvalidSection {
1556            section,
1557            reason: format!(
1558                "{packing_name} packing declares {expected_groups} groups, but the grid defines {} scan lines",
1559                lengths.len()
1560            ),
1561        });
1562    }
1563    let actual_values = lengths.iter().try_fold(0usize, |total, length| {
1564        total.checked_add(*length).ok_or(Error::ArithmeticOverflow {
1565            operation: "summing row-wise packing group lengths",
1566        })
1567    })?;
1568    if actual_values != expected_values {
1569        return Err(Error::DataLengthMismatch {
1570            expected: expected_values,
1571            actual: actual_values,
1572        });
1573    }
1574    Ok(())
1575}
1576
1577fn read_group_length(
1578    reader: &mut BitReader<'_>,
1579    params: &ComplexPackingParams,
1580    group_index: usize,
1581) -> Result<usize> {
1582    if params.scaled_group_length_bits as usize > u64::BITS as usize {
1583        return Err(Error::UnsupportedPackingWidth(
1584            params.scaled_group_length_bits,
1585        ));
1586    }
1587
1588    if group_index + 1 == params.num_groups {
1589        return Ok(params.true_length_last_group as usize);
1590    }
1591
1592    let scaled = reader
1593        .read(params.scaled_group_length_bits as usize)?
1594        .checked_mul(u64::from(params.group_length_increment))
1595        .ok_or(Error::ArithmeticOverflow {
1596            operation: "scaling complex-packing group length",
1597        })?;
1598    let length = u64::from(params.group_length_reference)
1599        .checked_add(scaled)
1600        .ok_or(Error::ArithmeticOverflow {
1601            operation: "computing complex-packing group length",
1602        })?;
1603    usize::try_from(length)
1604        .map_err(|_| Error::ValueOutOfRange("complex-packing group length exceeds usize".into()))
1605}
1606
1607fn read_spatial_descriptors(
1608    reader: &mut BitReader<'_>,
1609    params: SpatialDifferencingParams,
1610) -> Result<SpatialDescriptors> {
1611    if params.descriptor_octets == 0 {
1612        return Err(Error::InvalidSection {
1613            section: 5,
1614            reason: "spatial differencing requires at least one descriptor octet".into(),
1615        });
1616    }
1617
1618    let bit_count = usize::from(params.descriptor_octets) * 8;
1619    if bit_count > u64::BITS as usize {
1620        return Err(Error::InvalidSection {
1621            section: 5,
1622            reason: "spatial differencing descriptors wider than 8 octets are not supported".into(),
1623        });
1624    }
1625
1626    let first_value = reader.read_signed(bit_count)?;
1627    let second_value = if params.order == 2 {
1628        Some(reader.read_signed(bit_count)?)
1629    } else {
1630        None
1631    };
1632    for _ in usize::from(params.order.min(2))..params.order as usize {
1633        let _ = reader.read_signed(bit_count)?;
1634    }
1635    let overall_minimum = reader.read_signed(bit_count)?;
1636
1637    Ok(SpatialDescriptors {
1638        order: params.order,
1639        first_value,
1640        second_value,
1641        overall_minimum,
1642    })
1643}
1644
1645fn decode_constant_group_value(
1646    group_reference: u64,
1647    group_reference_bits: usize,
1648    missing_value_management: u8,
1649) -> Result<Option<i64>> {
1650    if is_missing_code(
1651        group_reference,
1652        group_reference_bits,
1653        missing_value_management,
1654        MissingKind::Primary,
1655    )? || is_missing_code(
1656        group_reference,
1657        group_reference_bits,
1658        missing_value_management,
1659        MissingKind::Secondary,
1660    )? {
1661        return Ok(None);
1662    }
1663
1664    let value = i64::try_from(group_reference)
1665        .map_err(|_| Error::ValueOutOfRange("group reference exceeds i64".into()))?;
1666    Ok(Some(value))
1667}
1668
1669fn decode_group_value(
1670    group_reference: i64,
1671    packed: u64,
1672    group_width: usize,
1673    missing_value_management: u8,
1674) -> Result<Option<i64>> {
1675    if is_missing_code(
1676        packed,
1677        group_width,
1678        missing_value_management,
1679        MissingKind::Primary,
1680    )? || is_missing_code(
1681        packed,
1682        group_width,
1683        missing_value_management,
1684        MissingKind::Secondary,
1685    )? {
1686        return Ok(None);
1687    }
1688
1689    let packed = i64::try_from(packed)
1690        .map_err(|_| Error::ValueOutOfRange("packed value exceeds i64".into()))?;
1691    let value = group_reference
1692        .checked_add(packed)
1693        .ok_or(Error::ArithmeticOverflow {
1694            operation: "reconstructing complex-packing value",
1695        })?;
1696    Ok(Some(value))
1697}
1698
1699fn is_missing_code(
1700    value: u64,
1701    bit_width: usize,
1702    missing_value_management: u8,
1703    kind: MissingKind,
1704) -> Result<bool> {
1705    let required_mode = match kind {
1706        MissingKind::Primary => 1,
1707        MissingKind::Secondary => 2,
1708    };
1709    if missing_value_management < required_mode {
1710        return Ok(false);
1711    }
1712
1713    let Some(code) = missing_code(bit_width, kind)? else {
1714        return Ok(false);
1715    };
1716    Ok(value == code)
1717}
1718
1719fn missing_code(bit_width: usize, kind: MissingKind) -> Result<Option<u64>> {
1720    if bit_width == 0 {
1721        return Ok(None);
1722    }
1723    if bit_width > u64::BITS as usize {
1724        return Err(Error::UnsupportedPackingWidth(bit_width as u8));
1725    }
1726
1727    let max_value = if bit_width == u64::BITS as usize {
1728        u64::MAX
1729    } else {
1730        (1u64 << bit_width) - 1
1731    };
1732
1733    let code = match kind {
1734        MissingKind::Primary => max_value,
1735        MissingKind::Secondary => max_value.saturating_sub(1),
1736    };
1737    Ok(Some(code))
1738}
1739
1740fn scale_complex_value<T: DecodeSample>(
1741    reference: f64,
1742    binary_factor: f64,
1743    decimal_factor: f64,
1744    value: Option<i64>,
1745) -> T {
1746    match value {
1747        Some(value) => T::from_f64(scale_decoded_value(
1748            reference,
1749            value as f64,
1750            binary_factor,
1751            decimal_factor,
1752        )),
1753        None => T::nan(),
1754    }
1755}
1756
1757fn scale_decoded_value(
1758    reference: f64,
1759    packed_delta: f64,
1760    binary_factor: f64,
1761    decimal_factor: f64,
1762) -> f64 {
1763    (reference + packed_delta * binary_factor) * decimal_factor
1764}
1765
1766struct GroupReaderLayout {
1767    reference_offset: usize,
1768    width_offset: usize,
1769    length_offset: usize,
1770    value_offset: usize,
1771}
1772
1773impl GroupReaderLayout {
1774    fn new(start_bit_offset: usize, params: &ComplexPackingParams) -> Result<Self> {
1775        if params.group_reference_bits as usize > u64::BITS as usize {
1776            return Err(Error::UnsupportedPackingWidth(params.group_reference_bits));
1777        }
1778        if params.group_width_bits as usize > u64::BITS as usize {
1779            return Err(Error::UnsupportedPackingWidth(params.group_width_bits));
1780        }
1781        if params.scaled_group_length_bits as usize > u64::BITS as usize {
1782            return Err(Error::UnsupportedPackingWidth(
1783                params.scaled_group_length_bits,
1784            ));
1785        }
1786
1787        let reference_offset = start_bit_offset;
1788        let width_offset = align_bit_offset(add_group_bits(
1789            reference_offset,
1790            params.num_groups,
1791            params.group_reference_bits as usize,
1792        )?)?;
1793        let length_offset = align_bit_offset(add_group_bits(
1794            width_offset,
1795            params.num_groups,
1796            params.group_width_bits as usize,
1797        )?)?;
1798        let value_offset = align_bit_offset(add_group_bits(
1799            length_offset,
1800            params.num_groups,
1801            params.scaled_group_length_bits as usize,
1802        )?)?;
1803
1804        Ok(Self {
1805            reference_offset,
1806            width_offset,
1807            length_offset,
1808            value_offset,
1809        })
1810    }
1811}
1812
1813fn add_group_bits(start_bit_offset: usize, count: usize, bits_per_group: usize) -> Result<usize> {
1814    count
1815        .checked_mul(bits_per_group)
1816        .and_then(|total_bits| start_bit_offset.checked_add(total_bits))
1817        .ok_or(Error::BitOffsetOverflow)
1818}
1819
1820fn align_bit_offset(bit_offset: usize) -> Result<usize> {
1821    let remainder = bit_offset % 8;
1822    if remainder == 0 {
1823        Ok(bit_offset)
1824    } else {
1825        bit_offset
1826            .checked_add(8 - remainder)
1827            .ok_or(Error::BitOffsetOverflow)
1828    }
1829}
1830
1831struct OutputCursor<'a, T> {
1832    output: &'a mut [T],
1833    bitmap: Option<&'a [u8]>,
1834    next_index: usize,
1835    values_written: usize,
1836}
1837
1838impl<'a, T: DecodeSample> OutputCursor<'a, T> {
1839    fn new(output: &'a mut [T], bitmap: Option<&'a [u8]>) -> Self {
1840        Self {
1841            output,
1842            bitmap,
1843            next_index: 0,
1844            values_written: 0,
1845        }
1846    }
1847
1848    fn push_present(&mut self, value: T) -> Result<()> {
1849        match self.bitmap {
1850            Some(bitmap) => {
1851                if self.advance_to_present(bitmap)? {
1852                    self.output[self.next_index] = value;
1853                    self.next_index += 1;
1854                    self.values_written += 1;
1855                    return Ok(());
1856                }
1857
1858                let expected = count_bitmap_present_points(bitmap, self.output.len())?;
1859                Err(Error::DataLengthMismatch {
1860                    expected,
1861                    actual: self.values_written + 1,
1862                })
1863            }
1864            None => {
1865                if self.next_index >= self.output.len() {
1866                    return Err(Error::DataLengthMismatch {
1867                        expected: self.output.len(),
1868                        actual: self.next_index + 1,
1869                    });
1870                }
1871
1872                self.output[self.next_index] = value;
1873                self.next_index += 1;
1874                self.values_written += 1;
1875                Ok(())
1876            }
1877        }
1878    }
1879
1880    fn take_dense(&mut self, count: usize) -> Result<Option<&mut [T]>> {
1881        if self.bitmap.is_some() {
1882            return Ok(None);
1883        }
1884        let start = self.next_index;
1885        let end = start.checked_add(count).ok_or(Error::ArithmeticOverflow {
1886            operation: "advancing dense decoded output",
1887        })?;
1888        if end > self.output.len() {
1889            return Err(Error::DataLengthMismatch {
1890                expected: self.output.len(),
1891                actual: end,
1892            });
1893        }
1894        self.next_index = end;
1895        self.values_written =
1896            self.values_written
1897                .checked_add(count)
1898                .ok_or(Error::ArithmeticOverflow {
1899                    operation: "counting dense decoded values",
1900                })?;
1901        Ok(Some(&mut self.output[start..end]))
1902    }
1903
1904    fn advance_to_present(&mut self, bitmap: &[u8]) -> Result<bool> {
1905        while self.next_index < self.output.len() {
1906            let byte_index = self.next_index / 8;
1907            let bit_index = self.next_index % 8;
1908            let byte = *bitmap.get(byte_index).ok_or(Error::DataLengthMismatch {
1909                expected: byte_index + 1,
1910                actual: bitmap.len(),
1911            })?;
1912            let remaining = byte & (u8::MAX >> bit_index);
1913            if remaining != 0 {
1914                let present_index = byte_index
1915                    .checked_mul(8)
1916                    .and_then(|base| base.checked_add(remaining.leading_zeros() as usize))
1917                    .ok_or(Error::BitOffsetOverflow)?;
1918                if present_index < self.output.len() {
1919                    self.output[self.next_index..present_index].fill(T::nan());
1920                    self.next_index = present_index;
1921                    return Ok(true);
1922                }
1923            }
1924
1925            let next_byte = byte_index
1926                .checked_add(1)
1927                .and_then(|index| index.checked_mul(8))
1928                .ok_or(Error::BitOffsetOverflow)?
1929                .min(self.output.len());
1930            self.output[self.next_index..next_byte].fill(T::nan());
1931            self.next_index = next_byte;
1932        }
1933        Ok(false)
1934    }
1935
1936    fn finish(mut self) -> Result<()> {
1937        if let Some(bitmap) = self.bitmap {
1938            if self.advance_to_present(bitmap)? {
1939                return Err(Error::DataLengthMismatch {
1940                    expected: count_bitmap_present_points(bitmap, self.output.len())?,
1941                    actual: self.values_written,
1942                });
1943            }
1944        }
1945
1946        if self.next_index != self.output.len() {
1947            return Err(Error::DataLengthMismatch {
1948                expected: self.output.len(),
1949                actual: self.next_index,
1950            });
1951        }
1952
1953        Ok(())
1954    }
1955    fn values_written(&self) -> usize {
1956        self.values_written
1957    }
1958}
1959
1960#[derive(Debug, Clone)]
1961struct SpatialDescriptors {
1962    order: u8,
1963    first_value: i64,
1964    second_value: Option<i64>,
1965    overall_minimum: i64,
1966}
1967
1968#[derive(Debug, Clone)]
1969struct SpatialRestoreState {
1970    descriptors: SpatialDescriptors,
1971    previous: Option<i64>,
1972    previous_difference: Option<i64>,
1973    non_missing_seen: usize,
1974}
1975
1976impl SpatialRestoreState {
1977    fn new(descriptors: SpatialDescriptors) -> Self {
1978        Self {
1979            descriptors,
1980            previous: None,
1981            previous_difference: None,
1982            non_missing_seen: 0,
1983        }
1984    }
1985
1986    fn restore(&mut self, value: Option<i64>) -> Result<Option<i64>> {
1987        let Some(value) = value else {
1988            return Ok(None);
1989        };
1990
1991        let restored = match self.descriptors.order {
1992            1 => self.restore_first_order(value)?,
1993            2 => self.restore_second_order(value)?,
1994            other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
1995        };
1996
1997        self.previous = Some(restored);
1998        self.non_missing_seen += 1;
1999        Ok(Some(restored))
2000    }
2001
2002    fn finish(self) -> Result<()> {
2003        let expected = match self.descriptors.order {
2004            1 => 1,
2005            2 => 2,
2006            other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
2007        };
2008        if self.non_missing_seen < expected {
2009            return Err(Error::DataLengthMismatch {
2010                expected,
2011                actual: self.non_missing_seen,
2012            });
2013        }
2014        Ok(())
2015    }
2016
2017    fn restore_first_order(&mut self, value: i64) -> Result<i64> {
2018        if self.non_missing_seen == 0 {
2019            return Ok(self.descriptors.first_value);
2020        }
2021
2022        let delta = value.checked_add(self.descriptors.overall_minimum).ok_or(
2023            Error::ArithmeticOverflow {
2024                operation: "restoring first-order spatial difference",
2025            },
2026        )?;
2027        self.previous
2028            .and_then(|previous| previous.checked_add(delta))
2029            .ok_or(Error::ArithmeticOverflow {
2030                operation: "restoring first-order spatial difference",
2031            })
2032    }
2033
2034    fn restore_second_order(&mut self, value: i64) -> Result<i64> {
2035        match self.non_missing_seen {
2036            0 => Ok(self.descriptors.first_value),
2037            1 => {
2038                let second_value = self.descriptors.second_value.ok_or(Error::InvalidSection {
2039                    section: 5,
2040                    reason: "missing second-order spatial differencing descriptors".into(),
2041                })?;
2042                self.previous_difference = second_value.checked_sub(self.descriptors.first_value);
2043                self.previous_difference.ok_or(Error::ArithmeticOverflow {
2044                    operation: "initializing second-order spatial difference",
2045                })?;
2046                Ok(second_value)
2047            }
2048            _ => {
2049                let second_difference = value.checked_add(self.descriptors.overall_minimum).ok_or(
2050                    Error::ArithmeticOverflow {
2051                        operation: "restoring second-order spatial difference",
2052                    },
2053                )?;
2054                let difference = self
2055                    .previous_difference
2056                    .and_then(|previous_difference| {
2057                        previous_difference.checked_add(second_difference)
2058                    })
2059                    .ok_or(Error::ArithmeticOverflow {
2060                        operation: "restoring second-order spatial difference",
2061                    })?;
2062                let next = self
2063                    .previous
2064                    .and_then(|previous| previous.checked_add(difference))
2065                    .ok_or(Error::ArithmeticOverflow {
2066                        operation: "restoring second-order spatial difference",
2067                    })?;
2068                self.previous_difference = Some(difference);
2069                Ok(next)
2070            }
2071        }
2072    }
2073}
2074
2075#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2076enum MissingKind {
2077    Primary,
2078    Secondary,
2079}
2080
2081#[cfg(test)]
2082mod tests {
2083    use super::{
2084        bitmap_payload, count_bitmap_present_points, decode_field, decode_payload, unpack_complex,
2085        unpack_simple, CcsdsBlockSize, CcsdsFlags, CcsdsPackingParams, ComplexPackingParams,
2086        DataRepresentation, IeeePackingParams, IeeePrecision, PngPackingParams,
2087        RunLengthPackingParams, ScaledPackingParams, SpatialDifferencingParams,
2088    };
2089    use crate::error::Error;
2090    use grib_core::binary::encode_ieee_binary128;
2091    use grib_core::bit::BitWriter;
2092
2093    #[test]
2094    fn unpack_simple_constant() {
2095        let params = ScaledPackingParams {
2096            encoded_values: 5,
2097            reference_value: 42.0,
2098            binary_scale: 0,
2099            decimal_scale: 0,
2100            bits_per_value: 0,
2101            original_field_type: 0,
2102        };
2103        let values = unpack_simple(&[], &params, 5).unwrap();
2104        assert_eq!(values, vec![42.0; 5]);
2105    }
2106
2107    #[test]
2108    fn unpack_simple_basic() {
2109        let params = ScaledPackingParams {
2110            encoded_values: 5,
2111            reference_value: 0.0,
2112            binary_scale: 0,
2113            decimal_scale: 0,
2114            bits_per_value: 8,
2115            original_field_type: 0,
2116        };
2117        let values = unpack_simple(&[0, 1, 2, 3, 4], &params, 5).unwrap();
2118        assert_eq!(values, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
2119    }
2120
2121    #[test]
2122    fn unpack_simple_dense_matches_byte_aligned_and_bit_packed_values() {
2123        let cases: &[(usize, &[u64])] = &[
2124            (7, &[1, 2, 3, 127]),
2125            (8, &[1, 17, 255]),
2126            (16, &[1, 0x1234, u16::MAX as u64]),
2127            (32, &[1, 0x1234_5678, u32::MAX as u64]),
2128            (64, &[1, 1 << 40, u32::MAX as u64 + 1]),
2129        ];
2130
2131        for &(bits, packed_values) in cases {
2132            let mut packed = BitWriter::new();
2133            for &value in packed_values {
2134                packed.write(value, bits).unwrap();
2135            }
2136            let params = ScaledPackingParams {
2137                encoded_values: packed_values.len(),
2138                reference_value: 0.0,
2139                binary_scale: 0,
2140                decimal_scale: 0,
2141                bits_per_value: bits as u8,
2142                original_field_type: 0,
2143            };
2144
2145            let decoded = unpack_simple(packed.as_bytes(), &params, packed_values.len()).unwrap();
2146            let expected: Vec<_> = packed_values.iter().map(|&value| value as f64).collect();
2147            assert_eq!(decoded, expected, "bits_per_value={bits}");
2148        }
2149    }
2150
2151    #[test]
2152    fn unpack_simple_applies_decimal_scale_to_reference_and_values() {
2153        let params = ScaledPackingParams {
2154            encoded_values: 2,
2155            reference_value: 10.0,
2156            binary_scale: 0,
2157            decimal_scale: 1,
2158            bits_per_value: 8,
2159            original_field_type: 0,
2160        };
2161
2162        let values = unpack_simple(&[0, 20], &params, 2).unwrap();
2163        assert!((values[0] - 1.0).abs() < 1e-12);
2164        assert!((values[1] - 3.0).abs() < 1e-12);
2165    }
2166
2167    #[test]
2168    fn decodes_all_ieee_packing_precisions() {
2169        let values = [1.0, -2.5, 65_536.125];
2170
2171        for precision in [
2172            IeeePrecision::Single,
2173            IeeePrecision::Double,
2174            IeeePrecision::Quadruple,
2175        ] {
2176            let payload = ieee_payload(&values, precision);
2177            let representation = DataRepresentation::IeeePacking(IeeePackingParams {
2178                encoded_values: values.len(),
2179                precision,
2180            });
2181            assert_eq!(
2182                decode_payload(&payload, &representation, None, values.len()).unwrap(),
2183                values
2184            );
2185        }
2186    }
2187
2188    #[test]
2189    fn decodes_ieee_values_through_a_bitmap() {
2190        let values = [1.0, -2.5, 65_536.125];
2191        let payload = ieee_payload(&values, IeeePrecision::Double);
2192        let representation = DataRepresentation::IeeePacking(IeeePackingParams {
2193            encoded_values: values.len(),
2194            precision: IeeePrecision::Double,
2195        });
2196
2197        let decoded = decode_payload(&payload, &representation, Some(&[0b1011_0000]), 4).unwrap();
2198        assert_eq!(decoded[0], 1.0);
2199        assert!(decoded[1].is_nan());
2200        assert_eq!(decoded[2..], values[1..]);
2201    }
2202
2203    #[test]
2204    fn rejects_truncated_and_trailing_ieee_payload_bytes() {
2205        let representation = DataRepresentation::IeeePacking(IeeePackingParams {
2206            encoded_values: 1,
2207            precision: IeeePrecision::Double,
2208        });
2209
2210        for payload in [&[0_u8; 7][..], &[0_u8; 9][..]] {
2211            assert!(matches!(
2212                decode_payload(payload, &representation, None, 1),
2213                Err(Error::DataLengthMismatch {
2214                    expected: 8,
2215                    actual
2216                }) if actual == payload.len()
2217            ));
2218        }
2219    }
2220
2221    #[test]
2222    fn decodes_run_length_levels_and_multidigit_runs() {
2223        let params = RunLengthPackingParams {
2224            encoded_values: 9,
2225            bits_per_value: 3,
2226            max_level_value: 2,
2227            decimal_scale: 1,
2228            level_values: vec![10, 20],
2229        };
2230        // With range 5, digits 2 and 1 encode seven repetitions after the
2231        // first level value: 1 + 2 + 1*5 = 8 total values.
2232        let payload = packed_symbols(3, &[1, 5, 4, 2]);
2233        let representation = DataRepresentation::RunLengthPacking(params);
2234
2235        assert_eq!(
2236            decode_payload(&payload, &representation, None, 9).unwrap(),
2237            [vec![1.0; 8], vec![2.0]].concat()
2238        );
2239    }
2240
2241    #[test]
2242    fn decodes_run_length_level_zero_as_missing() {
2243        let params = RunLengthPackingParams {
2244            encoded_values: 4,
2245            bits_per_value: 3,
2246            max_level_value: 2,
2247            decimal_scale: 0,
2248            level_values: vec![10, 20],
2249        };
2250        let payload = packed_symbols(3, &[0, 5, 1]);
2251        let representation = DataRepresentation::RunLengthPacking(params);
2252        let decoded = decode_payload(&payload, &representation, None, 4).unwrap();
2253
2254        assert!(decoded[..3].iter().all(|value| value.is_nan()));
2255        assert_eq!(decoded[3], 10.0);
2256    }
2257
2258    #[test]
2259    fn decodes_all_missing_run_length_field_through_bitmap() {
2260        let params = RunLengthPackingParams {
2261            encoded_values: 2,
2262            bits_per_value: 0,
2263            max_level_value: 0,
2264            decimal_scale: 0,
2265            level_values: Vec::new(),
2266        };
2267        let representation = DataRepresentation::RunLengthPacking(params);
2268        let decoded = decode_payload(&[], &representation, Some(&[0b1010_0000]), 4).unwrap();
2269
2270        assert!(decoded.iter().all(|value| value.is_nan()));
2271    }
2272
2273    #[test]
2274    fn rejects_malformed_run_length_streams() {
2275        let representation = DataRepresentation::RunLengthPacking(RunLengthPackingParams {
2276            encoded_values: 2,
2277            bits_per_value: 8,
2278            max_level_value: 2,
2279            decimal_scale: 0,
2280            level_values: vec![10, 20],
2281        });
2282
2283        let error = decode_payload(&[3], &representation, None, 2).unwrap_err();
2284        assert!(error.to_string().contains("run starts with code 3"));
2285
2286        let error = decode_payload(&[1], &representation, None, 2).unwrap_err();
2287        assert!(matches!(
2288            error,
2289            Error::DataLengthMismatch {
2290                expected: 2,
2291                actual: 1
2292            }
2293        ));
2294
2295        let error = decode_payload(&[1, 255], &representation, None, 2).unwrap_err();
2296        assert!(matches!(
2297            error,
2298            Error::DataLengthMismatch { expected: 2, .. }
2299        ));
2300
2301        for (params, reason) in [
2302            (
2303                RunLengthPackingParams {
2304                    encoded_values: 1,
2305                    bits_per_value: 65,
2306                    max_level_value: 0,
2307                    decimal_scale: 0,
2308                    level_values: Vec::new(),
2309                },
2310                "bits per value must not exceed 64",
2311            ),
2312            (
2313                RunLengthPackingParams {
2314                    encoded_values: 1,
2315                    bits_per_value: 0,
2316                    max_level_value: 0,
2317                    decimal_scale: 0,
2318                    level_values: vec![10],
2319                },
2320                "zero maximum level requires an empty level table",
2321            ),
2322        ] {
2323            let error = decode_payload(&[], &DataRepresentation::RunLengthPacking(params), None, 1)
2324                .unwrap_err();
2325            assert!(error.to_string().contains(reason), "{error}");
2326        }
2327
2328        let one_value = DataRepresentation::RunLengthPacking(RunLengthPackingParams {
2329            encoded_values: 1,
2330            bits_per_value: 3,
2331            max_level_value: 2,
2332            decimal_scale: 0,
2333            level_values: vec![10, 20],
2334        });
2335        let error = decode_payload(&[0b0010_0001], &one_value, None, 1).unwrap_err();
2336        assert!(error.to_string().contains("nonzero bits remain"));
2337    }
2338
2339    #[test]
2340    fn decodes_bitmap_masked_field() {
2341        let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
2342        let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
2343        let representation = DataRepresentation::SimplePacking(ScaledPackingParams {
2344            encoded_values: 3,
2345            reference_value: 0.0,
2346            binary_scale: 0,
2347            decimal_scale: 0,
2348            bits_per_value: 8,
2349            original_field_type: 0,
2350        });
2351
2352        let bitmap = bitmap_payload(&bitmap_section).unwrap();
2353        let decoded = decode_field(&data_section, &representation, bitmap, 4).unwrap();
2354        assert_eq!(decoded[0], 10.0);
2355        assert!(decoded[1].is_nan());
2356        assert_eq!(decoded[2], 20.0);
2357        assert_eq!(decoded[3], 30.0);
2358    }
2359
2360    fn ieee_payload(values: &[f64], precision: IeeePrecision) -> Vec<u8> {
2361        values
2362            .iter()
2363            .flat_map(|value| match precision {
2364                IeeePrecision::Single => Vec::from((*value as f32).to_be_bytes()),
2365                IeeePrecision::Double => Vec::from(value.to_be_bytes()),
2366                IeeePrecision::Quadruple => Vec::from(encode_ieee_binary128(*value)),
2367                _ => unreachable!("test covers all supported IEEE precisions"),
2368            })
2369            .collect()
2370    }
2371
2372    fn packed_symbols(bits: usize, symbols: &[u64]) -> Vec<u8> {
2373        let mut writer = BitWriter::new();
2374        for symbol in symbols {
2375            writer.write(*symbol, bits).unwrap();
2376        }
2377        writer.align_to_byte().unwrap();
2378        writer.into_bytes()
2379    }
2380
2381    #[test]
2382    fn decodes_bitmap_across_empty_bytes_and_a_partial_final_byte() {
2383        let data_section = [0, 0, 0, 7, 7, 11, 22];
2384        let bitmap_section = [0, 0, 0, 9, 6, 0, 0b0000_0000, 0b0010_0000, 0b1000_0000];
2385        let representation = DataRepresentation::SimplePacking(ScaledPackingParams {
2386            encoded_values: 2,
2387            reference_value: 0.0,
2388            binary_scale: 0,
2389            decimal_scale: 0,
2390            bits_per_value: 8,
2391            original_field_type: 0,
2392        });
2393
2394        let bitmap = bitmap_payload(&bitmap_section).unwrap();
2395        let decoded = decode_field(&data_section, &representation, bitmap, 19).unwrap();
2396        assert!(decoded[..10].iter().all(|value| value.is_nan()));
2397        assert_eq!(decoded[10], 11.0);
2398        assert!(decoded[11..16].iter().all(|value| value.is_nan()));
2399        assert_eq!(decoded[16], 22.0);
2400        assert!(decoded[17..].iter().all(|value| value.is_nan()));
2401    }
2402
2403    #[cfg(feature = "ccsds")]
2404    #[test]
2405    fn decodes_ccsds_unsigned_samples_across_container_widths() {
2406        for (bits, values) in [
2407            (8, vec![0, 1, 17, 255]),
2408            (16, vec![0, 1, 0x1234, 0xffff]),
2409            (20, vec![0, 1, 0x54321, 0xfffff]),
2410            (24, vec![0, 1, 0x654321, 0xffffff]),
2411            (32, vec![0, 1, 0x76543210, u32::MAX as i64]),
2412        ] {
2413            let flags = CcsdsFlags::PREPROCESS;
2414            let (payload, representation) = encode_ccsds_test_values(&values, bits, flags, 16);
2415            let decoded = decode_payload(&payload, &representation, None, values.len()).unwrap();
2416            let expected = values.iter().map(|value| *value as f64).collect::<Vec<_>>();
2417            assert_eq!(decoded, expected, "bits_per_value={bits}");
2418        }
2419    }
2420
2421    #[cfg(feature = "ccsds")]
2422    #[test]
2423    fn decodes_ccsds_signed_preprocessing_as_unsigned_grib_differences() {
2424        let values = [0, 1, 2047, 2048, 4095];
2425        let flags = CcsdsFlags::SIGNED | CcsdsFlags::PREPROCESS;
2426        let (payload, mut representation) = encode_ccsds_test_values(&values, 12, flags, 16);
2427        let DataRepresentation::CcsdsPacking(params) = &mut representation else {
2428            unreachable!();
2429        };
2430        *params = CcsdsPackingParams::new(
2431            ScaledPackingParams {
2432                encoded_values: values.len(),
2433                reference_value: 10.0,
2434                binary_scale: 1,
2435                decimal_scale: 1,
2436                bits_per_value: 12,
2437                original_field_type: 0,
2438            },
2439            flags,
2440            CcsdsBlockSize::SIXTEEN,
2441            128,
2442        )
2443        .unwrap();
2444
2445        let decoded = decode_payload(&payload, &representation, None, values.len()).unwrap();
2446        let expected = values
2447            .iter()
2448            .map(|value| (10.0 + *value as f64 * 2.0) / 10.0)
2449            .collect::<Vec<_>>();
2450        assert_float_values(&decoded, &expected);
2451    }
2452
2453    #[cfg(feature = "ccsds")]
2454    #[test]
2455    fn decodes_ccsds_restricted_stream_with_wire_to_codec_flag_mapping() {
2456        let values = [0, 1, 2, 3, 15, 7, 4, 0];
2457        let flags = CcsdsFlags::RESTRICTED | CcsdsFlags::PREPROCESS;
2458        let (payload, representation) = encode_ccsds_test_values(&values, 4, flags, 16);
2459
2460        let decoded = decode_payload(&payload, &representation, None, values.len()).unwrap();
2461        assert_eq!(
2462            decoded,
2463            values.iter().map(|value| *value as f64).collect::<Vec<_>>()
2464        );
2465        assert!(super::ccsds_decoder_flags(flags).contains(grib_aec::AecFlags::RESTRICTED));
2466    }
2467
2468    #[cfg(feature = "ccsds")]
2469    #[test]
2470    fn decodes_ccsds_nonstandard_even_block_when_not_enforced() {
2471        let values = (0..24).collect::<Vec<_>>();
2472        let flags = CcsdsFlags::PREPROCESS | CcsdsFlags::NOT_ENFORCE;
2473        let (payload, representation) = encode_ccsds_test_values(&values, 8, flags, 12);
2474
2475        let decoded = decode_payload(&payload, &representation, None, values.len()).unwrap();
2476        assert_eq!(
2477            decoded,
2478            values.iter().map(|value| *value as f64).collect::<Vec<_>>()
2479        );
2480    }
2481
2482    #[cfg(feature = "ccsds")]
2483    #[test]
2484    fn decodes_constant_ccsds_field_with_bitmap() {
2485        let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
2486        let representation = DataRepresentation::CcsdsPacking(
2487            CcsdsPackingParams::new(
2488                ScaledPackingParams {
2489                    encoded_values: 3,
2490                    reference_value: 42.0,
2491                    binary_scale: 0,
2492                    decimal_scale: 1,
2493                    bits_per_value: 0,
2494                    original_field_type: 0,
2495                },
2496                CcsdsFlags::DEFAULT,
2497                CcsdsBlockSize::THIRTY_TWO,
2498                128,
2499            )
2500            .unwrap(),
2501        );
2502
2503        let decoded = decode_payload(
2504            &[],
2505            &representation,
2506            bitmap_payload(&bitmap_section).unwrap(),
2507            4,
2508        )
2509        .unwrap();
2510        assert_eq!(decoded[0], 42.0);
2511        assert!(decoded[1].is_nan());
2512        assert_eq!(decoded[2], 42.0);
2513        assert_eq!(decoded[3], 42.0);
2514    }
2515
2516    #[cfg(not(feature = "ccsds"))]
2517    #[test]
2518    fn ccsds_packing_requires_ccsds_feature() {
2519        let representation = DataRepresentation::CcsdsPacking(
2520            CcsdsPackingParams::new(
2521                ScaledPackingParams {
2522                    encoded_values: 1,
2523                    reference_value: 0.0,
2524                    binary_scale: 0,
2525                    decimal_scale: 0,
2526                    bits_per_value: 8,
2527                    original_field_type: 0,
2528                },
2529                CcsdsFlags::DEFAULT,
2530                CcsdsBlockSize::THIRTY_TWO,
2531                128,
2532            )
2533            .unwrap(),
2534        );
2535
2536        let error = decode_payload(&[], &representation, None, 1).unwrap_err();
2537        assert!(matches!(error, Error::UnsupportedDataTemplate(42)));
2538    }
2539
2540    #[cfg(feature = "png")]
2541    #[test]
2542    fn decodes_png_packing_grayscale8() {
2543        let payload = encode_png(
2544            2,
2545            2,
2546            png::ColorType::Grayscale,
2547            png::BitDepth::Eight,
2548            &[1, 2, 3, 4],
2549        );
2550        let representation = DataRepresentation::PngPacking(PngPackingParams {
2551            packing: ScaledPackingParams {
2552                encoded_values: 4,
2553                reference_value: 10.0,
2554                binary_scale: 1,
2555                decimal_scale: 1,
2556                bits_per_value: 8,
2557                original_field_type: 0,
2558            },
2559        });
2560
2561        let decoded = decode_payload(&payload, &representation, None, 4).unwrap();
2562        assert_float_values(&decoded, &[1.2, 1.4, 1.6, 1.8]);
2563    }
2564
2565    #[cfg(feature = "png")]
2566    #[test]
2567    fn decodes_png_packing_grayscale16() {
2568        let payload = encode_png(
2569            2,
2570            1,
2571            png::ColorType::Grayscale,
2572            png::BitDepth::Sixteen,
2573            &[0x01, 0x00, 0x02, 0x00],
2574        );
2575        let representation = DataRepresentation::PngPacking(PngPackingParams {
2576            packing: ScaledPackingParams {
2577                encoded_values: 2,
2578                reference_value: 0.0,
2579                binary_scale: 0,
2580                decimal_scale: 0,
2581                bits_per_value: 16,
2582                original_field_type: 0,
2583            },
2584        });
2585
2586        let decoded = decode_payload(&payload, &representation, None, 2).unwrap();
2587        assert_eq!(decoded, vec![256.0, 512.0]);
2588    }
2589
2590    #[cfg(feature = "png")]
2591    #[test]
2592    fn decodes_png_packing_grayscale_subbyte() {
2593        let payload = encode_png(
2594            4,
2595            1,
2596            png::ColorType::Grayscale,
2597            png::BitDepth::Four,
2598            &[0x12, 0x34],
2599        );
2600        let representation = DataRepresentation::PngPacking(PngPackingParams {
2601            packing: ScaledPackingParams {
2602                encoded_values: 4,
2603                reference_value: 0.0,
2604                binary_scale: 0,
2605                decimal_scale: 0,
2606                bits_per_value: 4,
2607                original_field_type: 0,
2608            },
2609        });
2610
2611        let decoded = decode_payload(&payload, &representation, None, 4).unwrap();
2612        assert_eq!(decoded, vec![1.0, 2.0, 3.0, 4.0]);
2613    }
2614
2615    #[cfg(feature = "png")]
2616    #[test]
2617    fn decodes_png_packing_rgb8() {
2618        let payload = encode_png(
2619            2,
2620            1,
2621            png::ColorType::Rgb,
2622            png::BitDepth::Eight,
2623            &[0x01, 0x02, 0x03, 0x04, 0x05, 0x06],
2624        );
2625        let representation = DataRepresentation::PngPacking(PngPackingParams {
2626            packing: ScaledPackingParams {
2627                encoded_values: 2,
2628                reference_value: 0.0,
2629                binary_scale: 0,
2630                decimal_scale: 0,
2631                bits_per_value: 24,
2632                original_field_type: 0,
2633            },
2634        });
2635
2636        let decoded = decode_payload(&payload, &representation, None, 2).unwrap();
2637        assert_eq!(decoded, vec![0x01_02_03 as f64, 0x04_05_06 as f64]);
2638    }
2639
2640    #[cfg(feature = "png")]
2641    #[test]
2642    fn decodes_png_packing_rgba8() {
2643        let payload = encode_png(
2644            1,
2645            1,
2646            png::ColorType::Rgba,
2647            png::BitDepth::Eight,
2648            &[0x01, 0x02, 0x03, 0x04],
2649        );
2650        let representation = DataRepresentation::PngPacking(PngPackingParams {
2651            packing: ScaledPackingParams {
2652                encoded_values: 1,
2653                reference_value: 0.0,
2654                binary_scale: 0,
2655                decimal_scale: 0,
2656                bits_per_value: 32,
2657                original_field_type: 0,
2658            },
2659        });
2660
2661        let decoded = decode_payload(&payload, &representation, None, 1).unwrap();
2662        assert_eq!(decoded, vec![0x01_02_03_04 as f64]);
2663    }
2664
2665    #[cfg(feature = "png")]
2666    #[test]
2667    fn decodes_png_packing_with_bitmap() {
2668        let payload = encode_png(
2669            3,
2670            1,
2671            png::ColorType::Grayscale,
2672            png::BitDepth::Eight,
2673            &[10, 20, 30],
2674        );
2675        let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
2676        let representation = DataRepresentation::PngPacking(PngPackingParams {
2677            packing: ScaledPackingParams {
2678                encoded_values: 3,
2679                reference_value: 0.0,
2680                binary_scale: 0,
2681                decimal_scale: 0,
2682                bits_per_value: 8,
2683                original_field_type: 0,
2684            },
2685        });
2686
2687        let decoded = decode_payload(
2688            &payload,
2689            &representation,
2690            bitmap_payload(&bitmap_section).unwrap(),
2691            4,
2692        )
2693        .unwrap();
2694        assert_eq!(decoded[0], 10.0);
2695        assert!(decoded[1].is_nan());
2696        assert_eq!(decoded[2], 20.0);
2697        assert_eq!(decoded[3], 30.0);
2698    }
2699
2700    #[cfg(feature = "png")]
2701    #[test]
2702    fn rejects_png_header_dimension_mismatch_before_allocating_frame_buffer() {
2703        let mut payload = encode_png(1, 1, png::ColorType::Grayscale, png::BitDepth::Eight, &[1]);
2704        payload[16..20].copy_from_slice(&100_000u32.to_be_bytes());
2705        payload[20..24].copy_from_slice(&100_000u32.to_be_bytes());
2706        let crc = test_crc32(&payload[12..29]);
2707        payload[29..33].copy_from_slice(&crc.to_be_bytes());
2708
2709        let representation = DataRepresentation::PngPacking(PngPackingParams {
2710            packing: ScaledPackingParams {
2711                encoded_values: 1,
2712                reference_value: 0.0,
2713                binary_scale: 0,
2714                decimal_scale: 0,
2715                bits_per_value: 8,
2716                original_field_type: 0,
2717            },
2718        });
2719
2720        let err = decode_payload(&payload, &representation, None, 1).unwrap_err();
2721        assert!(matches!(
2722            err,
2723            Error::DataLengthMismatch {
2724                expected: 1,
2725                actual: 10_000_000_000,
2726            }
2727        ));
2728    }
2729
2730    #[cfg(feature = "jpeg2000")]
2731    #[test]
2732    fn rejects_jpeg2000_header_dimension_mismatch_before_decoding_codestream() {
2733        let mut payload = vec![0u8; 45];
2734        payload[..4].copy_from_slice(&[0xff, 0x4f, 0xff, 0x51]);
2735        payload[4..6].copy_from_slice(&41u16.to_be_bytes());
2736        payload[8..12].copy_from_slice(&100_000u32.to_be_bytes());
2737        payload[12..16].copy_from_slice(&100_000u32.to_be_bytes());
2738        payload[40..42].copy_from_slice(&1u16.to_be_bytes());
2739        payload[42] = 7;
2740        payload[43] = 1;
2741        payload[44] = 1;
2742
2743        let representation = DataRepresentation::Jpeg2000Packing(super::Jpeg2000PackingParams {
2744            packing: ScaledPackingParams {
2745                encoded_values: 1,
2746                reference_value: 0.0,
2747                binary_scale: 0,
2748                decimal_scale: 0,
2749                bits_per_value: 8,
2750                original_field_type: 0,
2751            },
2752            compression_type: 0,
2753            target_compression_ratio: 0,
2754        });
2755
2756        let err = decode_payload(&payload, &representation, None, 1).unwrap_err();
2757        assert!(matches!(
2758            err,
2759            Error::DataLengthMismatch {
2760                expected: 1,
2761                actual: 10_000_000_000,
2762            }
2763        ));
2764    }
2765
2766    #[cfg(feature = "jpeg2000")]
2767    #[test]
2768    fn reports_negative_unsigned_jpeg2000_samples_as_out_of_range() {
2769        let error = super::jpeg2000_raw_value(-1, 8).unwrap_err();
2770        assert!(matches!(error, Error::ValueOutOfRange(_)));
2771    }
2772
2773    #[cfg(feature = "png")]
2774    #[test]
2775    fn reports_incompatible_png_layout_as_invalid_section_seven() {
2776        let payload = encode_png(1, 1, png::ColorType::Rgb, png::BitDepth::Eight, &[1, 2, 3]);
2777        let representation = DataRepresentation::PngPacking(PngPackingParams {
2778            packing: ScaledPackingParams {
2779                encoded_values: 1,
2780                reference_value: 0.0,
2781                binary_scale: 0,
2782                decimal_scale: 0,
2783                bits_per_value: 8,
2784                original_field_type: 0,
2785            },
2786        });
2787
2788        let error = decode_payload(&payload, &representation, None, 1).unwrap_err();
2789        assert!(matches!(error, Error::InvalidSection { section: 7, .. }));
2790    }
2791
2792    #[cfg(not(feature = "png"))]
2793    #[test]
2794    fn png_packing_requires_png_feature() {
2795        let representation = DataRepresentation::PngPacking(PngPackingParams {
2796            packing: ScaledPackingParams {
2797                encoded_values: 1,
2798                reference_value: 0.0,
2799                binary_scale: 0,
2800                decimal_scale: 0,
2801                bits_per_value: 8,
2802                original_field_type: 0,
2803            },
2804        });
2805
2806        let err = decode_payload(&[], &representation, None, 1).unwrap_err();
2807        assert!(matches!(err, Error::UnsupportedDataTemplate(41)));
2808    }
2809
2810    #[cfg(not(feature = "jpeg2000"))]
2811    #[test]
2812    fn jpeg2000_packing_requires_jpeg2000_feature() {
2813        let representation = DataRepresentation::Jpeg2000Packing(super::Jpeg2000PackingParams {
2814            packing: ScaledPackingParams {
2815                encoded_values: 1,
2816                reference_value: 0.0,
2817                binary_scale: 0,
2818                decimal_scale: 0,
2819                bits_per_value: 8,
2820                original_field_type: 0,
2821            },
2822            compression_type: 1,
2823            target_compression_ratio: 255,
2824        });
2825
2826        let err = decode_payload(&[], &representation, None, 1).unwrap_err();
2827        assert!(matches!(err, Error::UnsupportedDataTemplate(40)));
2828    }
2829
2830    #[test]
2831    fn rejects_simple_packing_wider_than_u64() {
2832        let params = ScaledPackingParams {
2833            encoded_values: 1,
2834            reference_value: 0.0,
2835            binary_scale: 0,
2836            decimal_scale: 0,
2837            bits_per_value: 65,
2838            original_field_type: 0,
2839        };
2840        let err = unpack_simple(&[0; 9], &params, 1).unwrap_err();
2841        assert!(matches!(err, Error::UnsupportedPackingWidth(65)));
2842    }
2843
2844    #[test]
2845    fn rejects_encoded_value_count_mismatch_without_bitmap() {
2846        let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
2847        let representation = DataRepresentation::SimplePacking(ScaledPackingParams {
2848            encoded_values: 3,
2849            reference_value: 0.0,
2850            binary_scale: 0,
2851            decimal_scale: 0,
2852            bits_per_value: 8,
2853            original_field_type: 0,
2854        });
2855
2856        let err = decode_field(&data_section, &representation, None, 4).unwrap_err();
2857        assert!(matches!(
2858            err,
2859            Error::DataLengthMismatch {
2860                expected: 4,
2861                actual: 3,
2862            }
2863        ));
2864    }
2865
2866    #[test]
2867    fn rejects_bitmap_present_count_mismatch() {
2868        let data_section = [0, 0, 0, 7, 7, 10, 20];
2869        let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
2870        let representation = DataRepresentation::SimplePacking(ScaledPackingParams {
2871            encoded_values: 2,
2872            reference_value: 0.0,
2873            binary_scale: 0,
2874            decimal_scale: 0,
2875            bits_per_value: 8,
2876            original_field_type: 0,
2877        });
2878
2879        let bitmap = bitmap_payload(&bitmap_section).unwrap();
2880        let err = decode_field(&data_section, &representation, bitmap, 4).unwrap_err();
2881        assert!(matches!(
2882            err,
2883            Error::DataLengthMismatch {
2884                expected: 3,
2885                actual: 2,
2886            }
2887        ));
2888    }
2889
2890    #[test]
2891    fn counts_bitmap_present_points_with_partial_bytes() {
2892        let present = count_bitmap_present_points(&[0b1011_1111], 3).unwrap();
2893        assert_eq!(present, 2);
2894    }
2895
2896    #[cfg(feature = "ccsds")]
2897    fn encode_ccsds_test_values(
2898        values: &[i64],
2899        bits_per_value: u8,
2900        flags: CcsdsFlags,
2901        block_size: u8,
2902    ) -> (Vec<u8>, DataRepresentation) {
2903        let bytes_per_sample = usize::from(bits_per_value).div_ceil(8);
2904        let mask = if bits_per_value == 32 {
2905            u32::MAX
2906        } else {
2907            (1u32 << bits_per_value) - 1
2908        };
2909        let mut unpacked = Vec::with_capacity(values.len() * bytes_per_sample);
2910        for &value in values {
2911            let raw = (value as u32) & mask;
2912            let bytes = raw.to_be_bytes();
2913            unpacked.extend_from_slice(&bytes[4 - bytes_per_sample..]);
2914        }
2915
2916        let codec_params = grib_aec::AecParams::new(
2917            bits_per_value,
2918            block_size,
2919            128,
2920            super::ccsds_decoder_flags(flags),
2921        )
2922        .unwrap();
2923        let payload = grib_aec::encode(&unpacked, codec_params).unwrap();
2924        let representation = DataRepresentation::CcsdsPacking(
2925            CcsdsPackingParams::new(
2926                ScaledPackingParams {
2927                    encoded_values: values.len(),
2928                    reference_value: 0.0,
2929                    binary_scale: 0,
2930                    decimal_scale: 0,
2931                    bits_per_value,
2932                    original_field_type: 0,
2933                },
2934                flags,
2935                CcsdsBlockSize::new(block_size).unwrap(),
2936                128,
2937            )
2938            .unwrap(),
2939        );
2940        (payload, representation)
2941    }
2942
2943    #[test]
2944    fn unpacks_complex_packing_with_explicit_missing() {
2945        let params = ComplexPackingParams {
2946            encoded_values: 4,
2947            reference_value: 0.0,
2948            binary_scale: 0,
2949            decimal_scale: 0,
2950            group_reference_bits: 4,
2951            original_field_type: 0,
2952            group_splitting_method: 1,
2953            missing_value_management: 1,
2954            primary_missing_substitute: 0x6655_4433,
2955            secondary_missing_substitute: 0x2211_00ff,
2956            num_groups: 2,
2957            group_width_reference: 0,
2958            group_width_bits: 2,
2959            group_length_reference: 2,
2960            group_length_increment: 1,
2961            true_length_last_group: 2,
2962            scaled_group_length_bits: 0,
2963            spatial_differencing: None,
2964        };
2965
2966        assert_eq!(params.primary_missing_substitute(), Some(0x6655_4433));
2967        assert_eq!(params.secondary_missing_substitute(), None);
2968
2969        let values = unpack_complex(&[0x79, 0x90, 0x34], &params).unwrap();
2970        assert_eq!(values[0], 7.0);
2971        assert!(values[1].is_nan());
2972        assert_eq!(values[2], 9.0);
2973        assert!(values[3].is_nan());
2974    }
2975
2976    #[test]
2977    fn unpacks_complex_packing_applies_decimal_scale_to_reference_and_values() {
2978        let params = ComplexPackingParams {
2979            encoded_values: 2,
2980            reference_value: 10.0,
2981            binary_scale: 0,
2982            decimal_scale: 1,
2983            group_reference_bits: 4,
2984            original_field_type: 0,
2985            group_splitting_method: 1,
2986            missing_value_management: 0,
2987            primary_missing_substitute: u32::MAX,
2988            secondary_missing_substitute: u32::MAX,
2989            num_groups: 1,
2990            group_width_reference: 4,
2991            group_width_bits: 0,
2992            group_length_reference: 2,
2993            group_length_increment: 1,
2994            true_length_last_group: 2,
2995            scaled_group_length_bits: 0,
2996            spatial_differencing: None,
2997        };
2998
2999        let values = unpack_complex(&[0x10, 0x02], &params).unwrap();
3000        assert!((values[0] - 1.1).abs() < 1e-12);
3001        assert!((values[1] - 1.3).abs() < 1e-12);
3002    }
3003
3004    #[test]
3005    fn unpacks_complex_packing_with_second_order_spatial_differencing() {
3006        let params = ComplexPackingParams {
3007            encoded_values: 4,
3008            reference_value: 0.0,
3009            binary_scale: 0,
3010            decimal_scale: 0,
3011            group_reference_bits: 1,
3012            original_field_type: 0,
3013            group_splitting_method: 1,
3014            missing_value_management: 0,
3015            primary_missing_substitute: u32::MAX,
3016            secondary_missing_substitute: u32::MAX,
3017            num_groups: 1,
3018            group_width_reference: 1,
3019            group_width_bits: 0,
3020            group_length_reference: 4,
3021            group_length_increment: 1,
3022            true_length_last_group: 4,
3023            scaled_group_length_bits: 0,
3024            spatial_differencing: Some(SpatialDifferencingParams {
3025                order: 2,
3026                descriptor_octets: 2,
3027            }),
3028        };
3029
3030        let values =
3031            unpack_complex(&[0x00, 0x0A, 0x00, 0x0D, 0x00, 0x03, 0x00, 0x10], &params).unwrap();
3032        assert_eq!(values, vec![10.0, 13.0, 19.0, 29.0]);
3033    }
3034
3035    #[test]
3036    fn unpacks_complex_packing_with_spatial_differencing_and_missing_values() {
3037        let params = ComplexPackingParams {
3038            encoded_values: 4,
3039            reference_value: 0.0,
3040            binary_scale: 0,
3041            decimal_scale: 0,
3042            group_reference_bits: 1,
3043            original_field_type: 0,
3044            group_splitting_method: 1,
3045            missing_value_management: 1,
3046            primary_missing_substitute: u32::MAX,
3047            secondary_missing_substitute: u32::MAX,
3048            num_groups: 1,
3049            group_width_reference: 2,
3050            group_width_bits: 0,
3051            group_length_reference: 4,
3052            group_length_increment: 1,
3053            true_length_last_group: 4,
3054            scaled_group_length_bits: 0,
3055            spatial_differencing: Some(SpatialDifferencingParams {
3056                order: 1,
3057                descriptor_octets: 2,
3058            }),
3059        };
3060
3061        let values = unpack_complex(&[0x00, 0x0A, 0x00, 0x03, 0x00, 0x32], &params).unwrap();
3062        assert_eq!(values[0], 10.0);
3063        assert!(values[1].is_nan());
3064        assert_eq!(values[2], 13.0);
3065        assert_eq!(values[3], 18.0);
3066    }
3067
3068    #[cfg(feature = "png")]
3069    fn encode_png(
3070        width: u32,
3071        height: u32,
3072        color_type: png::ColorType,
3073        bit_depth: png::BitDepth,
3074        data: &[u8],
3075    ) -> Vec<u8> {
3076        let mut payload = Vec::new();
3077        {
3078            let mut encoder = png::Encoder::new(&mut payload, width, height);
3079            encoder.set_color(color_type);
3080            encoder.set_depth(bit_depth);
3081            let mut writer = encoder.write_header().unwrap();
3082            writer.write_image_data(data).unwrap();
3083        }
3084        payload
3085    }
3086
3087    #[cfg(feature = "png")]
3088    fn test_crc32(bytes: &[u8]) -> u32 {
3089        let mut crc = u32::MAX;
3090        for &byte in bytes {
3091            crc ^= u32::from(byte);
3092            for _ in 0..8 {
3093                let mask = 0u32.wrapping_sub(crc & 1);
3094                crc = (crc >> 1) ^ (0xedb8_8320 & mask);
3095            }
3096        }
3097        !crc
3098    }
3099
3100    #[cfg(feature = "png")]
3101    fn assert_float_values(actual: &[f64], expected: &[f64]) {
3102        assert_eq!(actual.len(), expected.len());
3103        for (actual, expected) in actual.iter().zip(expected) {
3104            assert!(
3105                (actual - expected).abs() < 1e-12,
3106                "expected {expected}, got {actual}"
3107            );
3108        }
3109    }
3110}