Skip to main content

grib_reader/
data.rs

1//! Data Representation Section (Section 5) and Data Section (Section 7) decoding.
2
3use crate::error::{Error, Result};
4use crate::util::grib_i16;
5
6/// Data representation template number and parameters.
7#[derive(Debug, Clone, PartialEq)]
8pub enum DataRepresentation {
9    /// Template 5.0: Simple packing.
10    SimplePacking(SimplePackingParams),
11    /// Template 5.2/5.3: Complex packing with optional spatial differencing.
12    ComplexPacking(ComplexPackingParams),
13    /// Unsupported template.
14    Unsupported(u16),
15}
16
17/// Parameters for simple packing (Template 5.0).
18#[derive(Debug, Clone, PartialEq)]
19pub struct SimplePackingParams {
20    pub encoded_values: usize,
21    pub reference_value: f32,
22    pub binary_scale: i16,
23    pub decimal_scale: i16,
24    pub bits_per_value: u8,
25    pub original_field_type: u8,
26}
27
28/// Parameters for complex packing (Templates 5.2 and 5.3).
29#[derive(Debug, Clone, PartialEq)]
30pub struct ComplexPackingParams {
31    pub encoded_values: usize,
32    pub reference_value: f32,
33    pub binary_scale: i16,
34    pub decimal_scale: i16,
35    pub group_reference_bits: u8,
36    pub original_field_type: u8,
37    pub group_splitting_method: u8,
38    pub missing_value_management: u8,
39    pub primary_missing_substitute: u32,
40    pub secondary_missing_substitute: u32,
41    pub num_groups: usize,
42    pub group_width_reference: u8,
43    pub group_width_bits: u8,
44    pub group_length_reference: u32,
45    pub group_length_increment: u8,
46    pub true_length_last_group: u32,
47    pub scaled_group_length_bits: u8,
48    pub spatial_differencing: Option<SpatialDifferencingParams>,
49}
50
51/// Parameters specific to template 5.3 spatial differencing.
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct SpatialDifferencingParams {
54    pub order: u8,
55    pub descriptor_octets: u8,
56}
57
58/// Numeric target type for decoded field values.
59pub trait DecodeSample: Copy + Sized {
60    fn from_f64(value: f64) -> Self;
61    fn nan() -> Self;
62}
63
64impl DecodeSample for f32 {
65    fn from_f64(value: f64) -> Self {
66        value as f32
67    }
68
69    fn nan() -> Self {
70        f32::NAN
71    }
72}
73
74impl DecodeSample for f64 {
75    fn from_f64(value: f64) -> Self {
76        value
77    }
78
79    fn nan() -> Self {
80        f64::NAN
81    }
82}
83
84impl DataRepresentation {
85    pub fn parse(section_bytes: &[u8]) -> Result<Self> {
86        if section_bytes.len() < 11 {
87            return Err(Error::InvalidSection {
88                section: 5,
89                reason: format!("expected at least 11 bytes, got {}", section_bytes.len()),
90            });
91        }
92        if section_bytes[4] != 5 {
93            return Err(Error::InvalidSection {
94                section: section_bytes[4],
95                reason: "not a data representation section".into(),
96            });
97        }
98
99        let template = u16::from_be_bytes(section_bytes[9..11].try_into().unwrap());
100        match template {
101            0 => parse_simple_packing(section_bytes),
102            2 => parse_complex_packing(section_bytes, false),
103            3 => parse_complex_packing(section_bytes, true),
104            _ => Ok(Self::Unsupported(template)),
105        }
106    }
107
108    pub fn encoded_values(&self) -> Option<usize> {
109        match self {
110            Self::SimplePacking(params) => Some(params.encoded_values),
111            Self::ComplexPacking(params) => Some(params.encoded_values),
112            Self::Unsupported(_) => None,
113        }
114    }
115}
116
117/// Decode Section 7 payload into field values, applying Section 6 bitmap when present.
118pub fn decode_field(
119    data_section: &[u8],
120    representation: &DataRepresentation,
121    bitmap_section: Option<&[u8]>,
122    num_grid_points: usize,
123) -> Result<Vec<f64>> {
124    if data_section.len() < 5 || data_section[4] != 7 {
125        return Err(Error::InvalidSection {
126            section: data_section.get(4).copied().unwrap_or(7),
127            reason: "not a data section".into(),
128        });
129    }
130
131    decode_payload(
132        &data_section[5..],
133        representation,
134        bitmap_section,
135        num_grid_points,
136    )
137}
138
139/// Decode Section 7 payload into a caller-provided buffer, applying Section 6
140/// bitmap when present.
141pub fn decode_field_into<T: DecodeSample>(
142    data_section: &[u8],
143    representation: &DataRepresentation,
144    bitmap_section: Option<&[u8]>,
145    num_grid_points: usize,
146    out: &mut [T],
147) -> Result<()> {
148    if data_section.len() < 5 || data_section[4] != 7 {
149        return Err(Error::InvalidSection {
150            section: data_section.get(4).copied().unwrap_or(7),
151            reason: "not a data section".into(),
152        });
153    }
154
155    decode_payload_into(
156        &data_section[5..],
157        representation,
158        bitmap_section,
159        num_grid_points,
160        out,
161    )
162}
163
164pub(crate) fn decode_payload(
165    payload: &[u8],
166    representation: &DataRepresentation,
167    bitmap_section: Option<&[u8]>,
168    num_grid_points: usize,
169) -> Result<Vec<f64>> {
170    let mut values = vec![0.0; num_grid_points];
171    decode_payload_into(
172        payload,
173        representation,
174        bitmap_section,
175        num_grid_points,
176        &mut values,
177    )?;
178    Ok(values)
179}
180
181pub(crate) fn decode_payload_into<T: DecodeSample>(
182    payload: &[u8],
183    representation: &DataRepresentation,
184    bitmap_section: Option<&[u8]>,
185    num_grid_points: usize,
186    out: &mut [T],
187) -> Result<()> {
188    if out.len() != num_grid_points {
189        return Err(Error::DataLengthMismatch {
190            expected: num_grid_points,
191            actual: out.len(),
192        });
193    }
194
195    let expected_values = match representation {
196        DataRepresentation::SimplePacking(params) => params.encoded_values,
197        DataRepresentation::ComplexPacking(params) => params.encoded_values,
198        DataRepresentation::Unsupported(template) => {
199            return Err(Error::UnsupportedDataTemplate(*template));
200        }
201    };
202    match bitmap_section {
203        Some(bitmap_payload) => {
204            let present_values = count_bitmap_present_points(bitmap_payload, num_grid_points)?;
205            if expected_values != present_values {
206                return Err(Error::DataLengthMismatch {
207                    expected: present_values,
208                    actual: expected_values,
209                });
210            }
211        }
212        None if expected_values != num_grid_points => {
213            return Err(Error::DataLengthMismatch {
214                expected: num_grid_points,
215                actual: expected_values,
216            });
217        }
218        None => {}
219    }
220
221    let mut output = OutputCursor::new(out, bitmap_section);
222    match representation {
223        DataRepresentation::SimplePacking(params) => {
224            unpack_simple_into(payload, params, expected_values, &mut output)?
225        }
226        DataRepresentation::ComplexPacking(params) => {
227            unpack_complex_into(payload, params, &mut output)?
228        }
229        DataRepresentation::Unsupported(_) => unreachable!(),
230    }
231    output.finish()
232}
233
234/// Parse bitmap presence from Section 6.
235pub fn bitmap_payload(section_bytes: &[u8]) -> Result<Option<&[u8]>> {
236    if section_bytes.len() < 6 {
237        return Err(Error::InvalidSection {
238            section: 6,
239            reason: format!("expected at least 6 bytes, got {}", section_bytes.len()),
240        });
241    }
242    if section_bytes[4] != 6 {
243        return Err(Error::InvalidSection {
244            section: section_bytes[4],
245            reason: "not a bitmap section".into(),
246        });
247    }
248
249    match section_bytes[5] {
250        255 => Ok(None),
251        0 => Ok(Some(&section_bytes[6..])),
252        indicator => Err(Error::UnsupportedBitmapIndicator(indicator)),
253    }
254}
255
256pub(crate) fn count_bitmap_present_points(
257    bitmap_payload: &[u8],
258    num_grid_points: usize,
259) -> Result<usize> {
260    let full_bytes = num_grid_points / 8;
261    let remaining_bits = num_grid_points % 8;
262    let required_bytes = full_bytes + usize::from(remaining_bits > 0);
263    if bitmap_payload.len() < required_bytes {
264        return Err(Error::DataLengthMismatch {
265            expected: required_bytes,
266            actual: bitmap_payload.len(),
267        });
268    }
269
270    let mut present = bitmap_payload[..full_bytes]
271        .iter()
272        .map(|byte| byte.count_ones() as usize)
273        .sum();
274    if remaining_bits > 0 {
275        let mask = u8::MAX << (8 - remaining_bits);
276        present += (bitmap_payload[full_bytes] & mask).count_ones() as usize;
277    }
278
279    Ok(present)
280}
281
282fn parse_simple_packing(data: &[u8]) -> Result<DataRepresentation> {
283    if data.len() < 21 {
284        return Err(Error::InvalidSection {
285            section: 5,
286            reason: format!("template 5.0 requires 21 bytes, got {}", data.len()),
287        });
288    }
289
290    let encoded_values = u32::from_be_bytes(data[5..9].try_into().unwrap()) as usize;
291    let reference_value = f32::from_be_bytes(data[11..15].try_into().unwrap());
292    let binary_scale = grib_i16(&data[15..17]).unwrap();
293    let decimal_scale = grib_i16(&data[17..19]).unwrap();
294    let bits_per_value = data[19];
295    let original_field_type = data[20];
296
297    Ok(DataRepresentation::SimplePacking(SimplePackingParams {
298        encoded_values,
299        reference_value,
300        binary_scale,
301        decimal_scale,
302        bits_per_value,
303        original_field_type,
304    }))
305}
306
307fn parse_complex_packing(
308    data: &[u8],
309    with_spatial_differencing: bool,
310) -> Result<DataRepresentation> {
311    let required = if with_spatial_differencing { 49 } else { 47 };
312    if data.len() < required {
313        return Err(Error::InvalidSection {
314            section: 5,
315            reason: format!(
316                "template 5.{} requires {required} bytes, got {}",
317                if with_spatial_differencing { 3 } else { 2 },
318                data.len()
319            ),
320        });
321    }
322
323    let group_splitting_method = data[21];
324    if group_splitting_method != 1 {
325        return Err(Error::UnsupportedGroupSplittingMethod(
326            group_splitting_method,
327        ));
328    }
329
330    let missing_value_management = data[22];
331    if missing_value_management > 2 {
332        return Err(Error::UnsupportedMissingValueManagement(
333            missing_value_management,
334        ));
335    }
336
337    let spatial_differencing = if with_spatial_differencing {
338        let order = data[47];
339        if !matches!(order, 1 | 2) {
340            return Err(Error::UnsupportedSpatialDifferencingOrder(order));
341        }
342        Some(SpatialDifferencingParams {
343            order,
344            descriptor_octets: data[48],
345        })
346    } else {
347        None
348    };
349
350    Ok(DataRepresentation::ComplexPacking(ComplexPackingParams {
351        encoded_values: u32::from_be_bytes(data[5..9].try_into().unwrap()) as usize,
352        reference_value: f32::from_be_bytes(data[11..15].try_into().unwrap()),
353        binary_scale: grib_i16(&data[15..17]).unwrap(),
354        decimal_scale: grib_i16(&data[17..19]).unwrap(),
355        group_reference_bits: data[19],
356        original_field_type: data[20],
357        group_splitting_method,
358        missing_value_management,
359        primary_missing_substitute: u32::from_be_bytes(data[23..27].try_into().unwrap()),
360        secondary_missing_substitute: u32::from_be_bytes(data[27..31].try_into().unwrap()),
361        num_groups: u32::from_be_bytes(data[31..35].try_into().unwrap()) as usize,
362        group_width_reference: data[35],
363        group_width_bits: data[36],
364        group_length_reference: u32::from_be_bytes(data[37..41].try_into().unwrap()),
365        group_length_increment: data[41],
366        true_length_last_group: u32::from_be_bytes(data[42..46].try_into().unwrap()),
367        scaled_group_length_bits: data[46],
368        spatial_differencing,
369    }))
370}
371
372/// Unpack simple-packed values.
373pub fn unpack_simple(
374    data_bytes: &[u8],
375    params: &SimplePackingParams,
376    num_values: usize,
377) -> Result<Vec<f64>> {
378    let mut values = vec![0.0; num_values];
379    let mut output = OutputCursor::new(&mut values, None);
380    unpack_simple_into(data_bytes, params, num_values, &mut output)?;
381    output.finish()?;
382    Ok(values)
383}
384
385fn unpack_simple_into<T: DecodeSample>(
386    data_bytes: &[u8],
387    params: &SimplePackingParams,
388    num_values: usize,
389    output: &mut OutputCursor<'_, T>,
390) -> Result<()> {
391    let bits = params.bits_per_value as usize;
392    let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
393    let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
394    let reference = params.reference_value as f64;
395    if bits == 0 {
396        let constant = T::from_f64(scale_decoded_value(
397            reference,
398            0.0,
399            binary_factor,
400            decimal_factor,
401        ));
402        for _ in 0..num_values {
403            output.push_present(constant)?;
404        }
405        return Ok(());
406    }
407    if bits > u64::BITS as usize {
408        return Err(Error::UnsupportedPackingWidth(params.bits_per_value));
409    }
410
411    let required_bits = bits
412        .checked_mul(num_values)
413        .ok_or_else(|| Error::Other("bit count overflow during unpacking".into()))?;
414    let required_bytes = required_bits.div_ceil(8);
415    if data_bytes.len() < required_bytes {
416        return Err(Error::Truncated {
417            offset: data_bytes.len() as u64,
418        });
419    }
420
421    let mut reader = BitReader::new(data_bytes);
422
423    for _ in 0..num_values {
424        let packed = reader.read(bits)?;
425        output.push_present(T::from_f64(scale_decoded_value(
426            reference,
427            packed as f64,
428            binary_factor,
429            decimal_factor,
430        )))?;
431    }
432
433    Ok(())
434}
435
436#[cfg(test)]
437fn unpack_complex(data_bytes: &[u8], params: &ComplexPackingParams) -> Result<Vec<f64>> {
438    let mut values = vec![0.0; params.encoded_values];
439    let mut output = OutputCursor::new(&mut values, None);
440    unpack_complex_into(data_bytes, params, &mut output)?;
441    output.finish()?;
442    Ok(values)
443}
444
445fn unpack_complex_into<T: DecodeSample>(
446    data_bytes: &[u8],
447    params: &ComplexPackingParams,
448    output: &mut OutputCursor<'_, T>,
449) -> Result<()> {
450    if params.num_groups == 0 {
451        return Err(Error::InvalidSection {
452            section: 5,
453            reason: "complex packing requires at least one group".into(),
454        });
455    }
456
457    let mut reader = BitReader::new(data_bytes);
458    let mut spatial = params
459        .spatial_differencing
460        .map(|spatial| read_spatial_descriptors(&mut reader, spatial))
461        .transpose()?
462        .map(SpatialRestoreState::new);
463
464    let layout = GroupReaderLayout::new(reader.bit_offset, params)?;
465    let mut reference_reader = BitReader::with_offset(data_bytes, layout.reference_offset);
466    let mut width_reader = BitReader::with_offset(data_bytes, layout.width_offset);
467    let mut length_reader = BitReader::with_offset(data_bytes, layout.length_offset);
468    let mut value_reader = BitReader::with_offset(data_bytes, layout.value_offset);
469    let binary_factor = 2.0_f64.powi(params.binary_scale as i32);
470    let decimal_factor = 10.0_f64.powi(-(params.decimal_scale as i32));
471    let reference = params.reference_value as f64;
472    let mut actual_total = 0usize;
473
474    for group_index in 0..params.num_groups {
475        let group_reference = reference_reader.read(params.group_reference_bits as usize)?;
476        let width_delta = width_reader.read(params.group_width_bits as usize)?;
477        let group_width = usize::from(params.group_width_reference)
478            .checked_add(width_delta as usize)
479            .ok_or_else(|| Error::Other("group width overflow".into()))?;
480        let group_length = read_group_length(&mut length_reader, params, group_index)?;
481
482        actual_total = actual_total
483            .checked_add(group_length)
484            .ok_or_else(|| Error::Other("group length overflow".into()))?;
485
486        if group_width == 0 {
487            let raw_value = decode_constant_group_value(
488                group_reference,
489                params.group_reference_bits as usize,
490                params.missing_value_management,
491            )?;
492            for _ in 0..group_length {
493                let value = spatial
494                    .as_mut()
495                    .map_or(Ok(raw_value), |state| state.restore(raw_value))?;
496                output.push_present(scale_complex_value(
497                    reference,
498                    binary_factor,
499                    decimal_factor,
500                    value,
501                ))?;
502            }
503            continue;
504        }
505
506        if group_width > u64::BITS as usize {
507            return Err(Error::UnsupportedPackingWidth(group_width as u8));
508        }
509
510        let group_reference = i64::try_from(group_reference)
511            .map_err(|_| Error::Other("group reference exceeds i64 range".into()))?;
512        for _ in 0..group_length {
513            let packed = value_reader.read(group_width)?;
514            let value = decode_group_value(
515                group_reference,
516                packed,
517                group_width,
518                params.missing_value_management,
519            )?;
520            let value = spatial
521                .as_mut()
522                .map_or(Ok(value), |state| state.restore(value))?;
523            output.push_present(scale_complex_value(
524                reference,
525                binary_factor,
526                decimal_factor,
527                value,
528            ))?;
529        }
530    }
531
532    if actual_total != params.encoded_values {
533        return Err(Error::DataLengthMismatch {
534            expected: params.encoded_values,
535            actual: actual_total,
536        });
537    }
538
539    if output.values_written() != params.encoded_values {
540        return Err(Error::DataLengthMismatch {
541            expected: params.encoded_values,
542            actual: output.values_written(),
543        });
544    }
545
546    if let Some(spatial) = spatial {
547        spatial.finish()?;
548    }
549
550    Ok(())
551}
552
553fn read_group_length(
554    reader: &mut BitReader<'_>,
555    params: &ComplexPackingParams,
556    group_index: usize,
557) -> Result<usize> {
558    if params.scaled_group_length_bits as usize > u64::BITS as usize {
559        return Err(Error::UnsupportedPackingWidth(
560            params.scaled_group_length_bits,
561        ));
562    }
563
564    if group_index + 1 == params.num_groups {
565        return Ok(params.true_length_last_group as usize);
566    }
567
568    let scaled = reader
569        .read(params.scaled_group_length_bits as usize)?
570        .checked_mul(u64::from(params.group_length_increment))
571        .ok_or_else(|| Error::Other("group length overflow".into()))?;
572    let length = u64::from(params.group_length_reference)
573        .checked_add(scaled)
574        .ok_or_else(|| Error::Other("group length overflow".into()))?;
575    usize::try_from(length).map_err(|_| Error::Other("group length overflow".into()))
576}
577
578fn read_spatial_descriptors(
579    reader: &mut BitReader<'_>,
580    params: SpatialDifferencingParams,
581) -> Result<SpatialDescriptors> {
582    if params.descriptor_octets == 0 {
583        return Err(Error::InvalidSection {
584            section: 5,
585            reason: "spatial differencing requires at least one descriptor octet".into(),
586        });
587    }
588
589    let bit_count = usize::from(params.descriptor_octets) * 8;
590    if bit_count > u64::BITS as usize {
591        return Err(Error::Other(
592            "spatial differencing descriptors wider than 8 octets are not supported".into(),
593        ));
594    }
595
596    let first_value = reader.read_signed(bit_count)?;
597    let second_value = if params.order == 2 {
598        Some(reader.read_signed(bit_count)?)
599    } else {
600        None
601    };
602    for _ in usize::from(params.order.min(2))..params.order as usize {
603        let _ = reader.read_signed(bit_count)?;
604    }
605    let overall_minimum = reader.read_signed(bit_count)?;
606
607    Ok(SpatialDescriptors {
608        order: params.order,
609        first_value,
610        second_value,
611        overall_minimum,
612    })
613}
614
615fn decode_constant_group_value(
616    group_reference: u64,
617    group_reference_bits: usize,
618    missing_value_management: u8,
619) -> Result<Option<i64>> {
620    if is_missing_code(
621        group_reference,
622        group_reference_bits,
623        missing_value_management,
624        MissingKind::Primary,
625    )? || is_missing_code(
626        group_reference,
627        group_reference_bits,
628        missing_value_management,
629        MissingKind::Secondary,
630    )? {
631        return Ok(None);
632    }
633
634    let value = i64::try_from(group_reference)
635        .map_err(|_| Error::Other("group reference exceeds i64 range".into()))?;
636    Ok(Some(value))
637}
638
639fn decode_group_value(
640    group_reference: i64,
641    packed: u64,
642    group_width: usize,
643    missing_value_management: u8,
644) -> Result<Option<i64>> {
645    if is_missing_code(
646        packed,
647        group_width,
648        missing_value_management,
649        MissingKind::Primary,
650    )? || is_missing_code(
651        packed,
652        group_width,
653        missing_value_management,
654        MissingKind::Secondary,
655    )? {
656        return Ok(None);
657    }
658
659    let packed =
660        i64::try_from(packed).map_err(|_| Error::Other("packed value exceeds i64 range".into()))?;
661    let value = group_reference
662        .checked_add(packed)
663        .ok_or_else(|| Error::Other("decoded complex packing value overflow".into()))?;
664    Ok(Some(value))
665}
666
667fn is_missing_code(
668    value: u64,
669    bit_width: usize,
670    missing_value_management: u8,
671    kind: MissingKind,
672) -> Result<bool> {
673    let required_mode = match kind {
674        MissingKind::Primary => 1,
675        MissingKind::Secondary => 2,
676    };
677    if missing_value_management < required_mode {
678        return Ok(false);
679    }
680
681    let Some(code) = missing_code(bit_width, kind)? else {
682        return Ok(false);
683    };
684    Ok(value == code)
685}
686
687fn missing_code(bit_width: usize, kind: MissingKind) -> Result<Option<u64>> {
688    if bit_width == 0 {
689        return Ok(None);
690    }
691    if bit_width > u64::BITS as usize {
692        return Err(Error::UnsupportedPackingWidth(bit_width as u8));
693    }
694
695    let max_value = if bit_width == u64::BITS as usize {
696        u64::MAX
697    } else {
698        (1u64 << bit_width) - 1
699    };
700
701    let code = match kind {
702        MissingKind::Primary => max_value,
703        MissingKind::Secondary => max_value.saturating_sub(1),
704    };
705    Ok(Some(code))
706}
707
708fn scale_complex_value<T: DecodeSample>(
709    reference: f64,
710    binary_factor: f64,
711    decimal_factor: f64,
712    value: Option<i64>,
713) -> T {
714    match value {
715        Some(value) => T::from_f64(scale_decoded_value(
716            reference,
717            value as f64,
718            binary_factor,
719            decimal_factor,
720        )),
721        None => T::nan(),
722    }
723}
724
725fn scale_decoded_value(
726    reference: f64,
727    packed_delta: f64,
728    binary_factor: f64,
729    decimal_factor: f64,
730) -> f64 {
731    (reference + packed_delta * binary_factor) * decimal_factor
732}
733
734fn bitmap_bit(bitmap_payload: &[u8], index: usize) -> Result<bool> {
735    let byte_index = index / 8;
736    let bit_index = index % 8;
737    let byte = bitmap_payload
738        .get(byte_index)
739        .copied()
740        .ok_or(Error::DataLengthMismatch {
741            expected: byte_index + 1,
742            actual: bitmap_payload.len(),
743        })?;
744    Ok(((byte >> (7 - bit_index)) & 1) != 0)
745}
746
747struct GroupReaderLayout {
748    reference_offset: usize,
749    width_offset: usize,
750    length_offset: usize,
751    value_offset: usize,
752}
753
754impl GroupReaderLayout {
755    fn new(start_bit_offset: usize, params: &ComplexPackingParams) -> Result<Self> {
756        if params.group_reference_bits as usize > u64::BITS as usize {
757            return Err(Error::UnsupportedPackingWidth(params.group_reference_bits));
758        }
759        if params.group_width_bits as usize > u64::BITS as usize {
760            return Err(Error::UnsupportedPackingWidth(params.group_width_bits));
761        }
762        if params.scaled_group_length_bits as usize > u64::BITS as usize {
763            return Err(Error::UnsupportedPackingWidth(
764                params.scaled_group_length_bits,
765            ));
766        }
767
768        let reference_offset = start_bit_offset;
769        let width_offset = align_bit_offset(add_group_bits(
770            reference_offset,
771            params.num_groups,
772            params.group_reference_bits as usize,
773        )?)?;
774        let length_offset = align_bit_offset(add_group_bits(
775            width_offset,
776            params.num_groups,
777            params.group_width_bits as usize,
778        )?)?;
779        let value_offset = align_bit_offset(add_group_bits(
780            length_offset,
781            params.num_groups,
782            params.scaled_group_length_bits as usize,
783        )?)?;
784
785        Ok(Self {
786            reference_offset,
787            width_offset,
788            length_offset,
789            value_offset,
790        })
791    }
792}
793
794fn add_group_bits(start_bit_offset: usize, count: usize, bits_per_group: usize) -> Result<usize> {
795    count
796        .checked_mul(bits_per_group)
797        .and_then(|total_bits| start_bit_offset.checked_add(total_bits))
798        .ok_or_else(|| Error::Other("bit offset overflow".into()))
799}
800
801fn align_bit_offset(bit_offset: usize) -> Result<usize> {
802    let remainder = bit_offset % 8;
803    if remainder == 0 {
804        Ok(bit_offset)
805    } else {
806        bit_offset
807            .checked_add(8 - remainder)
808            .ok_or_else(|| Error::Other("bit offset overflow".into()))
809    }
810}
811
812struct OutputCursor<'a, T> {
813    output: &'a mut [T],
814    bitmap: Option<&'a [u8]>,
815    next_index: usize,
816    values_written: usize,
817}
818
819impl<'a, T: DecodeSample> OutputCursor<'a, T> {
820    fn new(output: &'a mut [T], bitmap: Option<&'a [u8]>) -> Self {
821        Self {
822            output,
823            bitmap,
824            next_index: 0,
825            values_written: 0,
826        }
827    }
828
829    fn push_present(&mut self, value: T) -> Result<()> {
830        match self.bitmap {
831            Some(bitmap) => {
832                while self.next_index < self.output.len() {
833                    if bitmap_bit(bitmap, self.next_index)? {
834                        self.output[self.next_index] = value;
835                        self.next_index += 1;
836                        self.values_written += 1;
837                        return Ok(());
838                    }
839
840                    self.output[self.next_index] = T::nan();
841                    self.next_index += 1;
842                }
843
844                let expected = count_bitmap_present_points(bitmap, self.output.len())?;
845                Err(Error::DataLengthMismatch {
846                    expected,
847                    actual: self.values_written + 1,
848                })
849            }
850            None => {
851                if self.next_index >= self.output.len() {
852                    return Err(Error::DataLengthMismatch {
853                        expected: self.output.len(),
854                        actual: self.next_index + 1,
855                    });
856                }
857
858                self.output[self.next_index] = value;
859                self.next_index += 1;
860                self.values_written += 1;
861                Ok(())
862            }
863        }
864    }
865
866    fn finish(mut self) -> Result<()> {
867        if let Some(bitmap) = self.bitmap {
868            while self.next_index < self.output.len() {
869                if bitmap_bit(bitmap, self.next_index)? {
870                    return Err(Error::DataLengthMismatch {
871                        expected: count_bitmap_present_points(bitmap, self.output.len())?,
872                        actual: self.values_written,
873                    });
874                }
875                self.output[self.next_index] = T::nan();
876                self.next_index += 1;
877            }
878        }
879
880        if self.next_index != self.output.len() {
881            return Err(Error::DataLengthMismatch {
882                expected: self.output.len(),
883                actual: self.next_index,
884            });
885        }
886
887        Ok(())
888    }
889    fn values_written(&self) -> usize {
890        self.values_written
891    }
892}
893
894struct BitReader<'a> {
895    data: &'a [u8],
896    bit_offset: usize,
897}
898
899impl<'a> BitReader<'a> {
900    fn new(data: &'a [u8]) -> Self {
901        Self {
902            data,
903            bit_offset: 0,
904        }
905    }
906
907    fn with_offset(data: &'a [u8], bit_offset: usize) -> Self {
908        Self { data, bit_offset }
909    }
910
911    fn read(&mut self, bit_count: usize) -> Result<u64> {
912        if bit_count == 0 {
913            return Ok(0);
914        }
915
916        let mut remaining = bit_count;
917        let mut value = 0u64;
918
919        while remaining > 0 {
920            let byte_index = self.bit_offset / 8;
921            let bit_index = self.bit_offset % 8;
922            let byte = *self.data.get(byte_index).ok_or(Error::Truncated {
923                offset: byte_index as u64,
924            })?;
925            let available = 8 - bit_index;
926            let take = remaining.min(available);
927            let mask = ((1u16 << take) - 1) as u8;
928            let shift = available - take;
929            let bits = (byte >> shift) & mask;
930
931            value = (value << take) | bits as u64;
932            self.bit_offset += take;
933            remaining -= take;
934        }
935
936        Ok(value)
937    }
938
939    fn read_signed(&mut self, bit_count: usize) -> Result<i64> {
940        let value = self.read(bit_count)?;
941        if bit_count == 0 {
942            return Ok(0);
943        }
944
945        let sign_mask = 1u64 << (bit_count - 1);
946        if value & sign_mask == 0 {
947            return i64::try_from(value)
948                .map_err(|_| Error::Other("signed value exceeds i64 range".into()));
949        }
950
951        let magnitude_mask = sign_mask - 1;
952        let magnitude = value & magnitude_mask;
953        let magnitude = i64::try_from(magnitude)
954            .map_err(|_| Error::Other("signed value exceeds i64 range".into()))?;
955        Ok(-magnitude)
956    }
957}
958
959#[derive(Debug, Clone)]
960struct SpatialDescriptors {
961    order: u8,
962    first_value: i64,
963    second_value: Option<i64>,
964    overall_minimum: i64,
965}
966
967#[derive(Debug, Clone)]
968struct SpatialRestoreState {
969    descriptors: SpatialDescriptors,
970    previous: Option<i64>,
971    previous_difference: Option<i64>,
972    non_missing_seen: usize,
973}
974
975impl SpatialRestoreState {
976    fn new(descriptors: SpatialDescriptors) -> Self {
977        Self {
978            descriptors,
979            previous: None,
980            previous_difference: None,
981            non_missing_seen: 0,
982        }
983    }
984
985    fn restore(&mut self, value: Option<i64>) -> Result<Option<i64>> {
986        let Some(value) = value else {
987            return Ok(None);
988        };
989
990        let restored = match self.descriptors.order {
991            1 => self.restore_first_order(value)?,
992            2 => self.restore_second_order(value)?,
993            other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
994        };
995
996        self.previous = Some(restored);
997        self.non_missing_seen += 1;
998        Ok(Some(restored))
999    }
1000
1001    fn finish(self) -> Result<()> {
1002        let expected = match self.descriptors.order {
1003            1 => 1,
1004            2 => 2,
1005            other => return Err(Error::UnsupportedSpatialDifferencingOrder(other)),
1006        };
1007        if self.non_missing_seen < expected {
1008            return Err(Error::DataLengthMismatch {
1009                expected,
1010                actual: self.non_missing_seen,
1011            });
1012        }
1013        Ok(())
1014    }
1015
1016    fn restore_first_order(&mut self, value: i64) -> Result<i64> {
1017        if self.non_missing_seen == 0 {
1018            return Ok(self.descriptors.first_value);
1019        }
1020
1021        let delta = value
1022            .checked_add(self.descriptors.overall_minimum)
1023            .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1024        self.previous
1025            .and_then(|previous| previous.checked_add(delta))
1026            .ok_or_else(|| Error::Other("spatial differencing overflow".into()))
1027    }
1028
1029    fn restore_second_order(&mut self, value: i64) -> Result<i64> {
1030        match self.non_missing_seen {
1031            0 => Ok(self.descriptors.first_value),
1032            1 => {
1033                let second_value = self.descriptors.second_value.ok_or(Error::InvalidSection {
1034                    section: 5,
1035                    reason: "missing second-order spatial differencing descriptors".into(),
1036                })?;
1037                self.previous_difference = second_value.checked_sub(self.descriptors.first_value);
1038                self.previous_difference
1039                    .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1040                Ok(second_value)
1041            }
1042            _ => {
1043                let second_difference = value
1044                    .checked_add(self.descriptors.overall_minimum)
1045                    .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1046                let difference = self
1047                    .previous_difference
1048                    .and_then(|previous_difference| {
1049                        previous_difference.checked_add(second_difference)
1050                    })
1051                    .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1052                let next = self
1053                    .previous
1054                    .and_then(|previous| previous.checked_add(difference))
1055                    .ok_or_else(|| Error::Other("spatial differencing overflow".into()))?;
1056                self.previous_difference = Some(difference);
1057                Ok(next)
1058            }
1059        }
1060    }
1061}
1062
1063#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1064enum MissingKind {
1065    Primary,
1066    Secondary,
1067}
1068
1069#[cfg(test)]
1070mod tests {
1071    use super::{
1072        bitmap_payload, count_bitmap_present_points, decode_field, unpack_complex, unpack_simple,
1073        ComplexPackingParams, DataRepresentation, SimplePackingParams, SpatialDifferencingParams,
1074    };
1075    use crate::error::Error;
1076
1077    #[test]
1078    fn unpack_simple_constant() {
1079        let params = SimplePackingParams {
1080            encoded_values: 5,
1081            reference_value: 42.0,
1082            binary_scale: 0,
1083            decimal_scale: 0,
1084            bits_per_value: 0,
1085            original_field_type: 0,
1086        };
1087        let values = unpack_simple(&[], &params, 5).unwrap();
1088        assert_eq!(values, vec![42.0; 5]);
1089    }
1090
1091    #[test]
1092    fn unpack_simple_basic() {
1093        let params = SimplePackingParams {
1094            encoded_values: 5,
1095            reference_value: 0.0,
1096            binary_scale: 0,
1097            decimal_scale: 0,
1098            bits_per_value: 8,
1099            original_field_type: 0,
1100        };
1101        let values = unpack_simple(&[0, 1, 2, 3, 4], &params, 5).unwrap();
1102        assert_eq!(values, vec![0.0, 1.0, 2.0, 3.0, 4.0]);
1103    }
1104
1105    #[test]
1106    fn unpack_simple_applies_decimal_scale_to_reference_and_values() {
1107        let params = SimplePackingParams {
1108            encoded_values: 2,
1109            reference_value: 10.0,
1110            binary_scale: 0,
1111            decimal_scale: 1,
1112            bits_per_value: 8,
1113            original_field_type: 0,
1114        };
1115
1116        let values = unpack_simple(&[0, 20], &params, 2).unwrap();
1117        assert!((values[0] - 1.0).abs() < 1e-12);
1118        assert!((values[1] - 3.0).abs() < 1e-12);
1119    }
1120
1121    #[test]
1122    fn decodes_bitmap_masked_field() {
1123        let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
1124        let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
1125        let representation = DataRepresentation::SimplePacking(SimplePackingParams {
1126            encoded_values: 3,
1127            reference_value: 0.0,
1128            binary_scale: 0,
1129            decimal_scale: 0,
1130            bits_per_value: 8,
1131            original_field_type: 0,
1132        });
1133
1134        let bitmap = bitmap_payload(&bitmap_section).unwrap();
1135        let decoded = decode_field(&data_section, &representation, bitmap, 4).unwrap();
1136        assert_eq!(decoded[0], 10.0);
1137        assert!(decoded[1].is_nan());
1138        assert_eq!(decoded[2], 20.0);
1139        assert_eq!(decoded[3], 30.0);
1140    }
1141
1142    #[test]
1143    fn rejects_simple_packing_wider_than_u64() {
1144        let params = SimplePackingParams {
1145            encoded_values: 1,
1146            reference_value: 0.0,
1147            binary_scale: 0,
1148            decimal_scale: 0,
1149            bits_per_value: 65,
1150            original_field_type: 0,
1151        };
1152        let err = unpack_simple(&[0; 9], &params, 1).unwrap_err();
1153        assert!(matches!(err, Error::UnsupportedPackingWidth(65)));
1154    }
1155
1156    #[test]
1157    fn rejects_encoded_value_count_mismatch_without_bitmap() {
1158        let data_section = [0, 0, 0, 8, 7, 10, 20, 30];
1159        let representation = DataRepresentation::SimplePacking(SimplePackingParams {
1160            encoded_values: 3,
1161            reference_value: 0.0,
1162            binary_scale: 0,
1163            decimal_scale: 0,
1164            bits_per_value: 8,
1165            original_field_type: 0,
1166        });
1167
1168        let err = decode_field(&data_section, &representation, None, 4).unwrap_err();
1169        assert!(matches!(
1170            err,
1171            Error::DataLengthMismatch {
1172                expected: 4,
1173                actual: 3,
1174            }
1175        ));
1176    }
1177
1178    #[test]
1179    fn rejects_bitmap_present_count_mismatch() {
1180        let data_section = [0, 0, 0, 7, 7, 10, 20];
1181        let bitmap_section = [0, 0, 0, 7, 6, 0, 0b1011_0000];
1182        let representation = DataRepresentation::SimplePacking(SimplePackingParams {
1183            encoded_values: 2,
1184            reference_value: 0.0,
1185            binary_scale: 0,
1186            decimal_scale: 0,
1187            bits_per_value: 8,
1188            original_field_type: 0,
1189        });
1190
1191        let bitmap = bitmap_payload(&bitmap_section).unwrap();
1192        let err = decode_field(&data_section, &representation, bitmap, 4).unwrap_err();
1193        assert!(matches!(
1194            err,
1195            Error::DataLengthMismatch {
1196                expected: 3,
1197                actual: 2,
1198            }
1199        ));
1200    }
1201
1202    #[test]
1203    fn counts_bitmap_present_points_with_partial_bytes() {
1204        let present = count_bitmap_present_points(&[0b1011_1111], 3).unwrap();
1205        assert_eq!(present, 2);
1206    }
1207
1208    #[test]
1209    fn unpacks_complex_packing_with_explicit_missing() {
1210        let params = ComplexPackingParams {
1211            encoded_values: 4,
1212            reference_value: 0.0,
1213            binary_scale: 0,
1214            decimal_scale: 0,
1215            group_reference_bits: 4,
1216            original_field_type: 0,
1217            group_splitting_method: 1,
1218            missing_value_management: 1,
1219            primary_missing_substitute: u32::MAX,
1220            secondary_missing_substitute: u32::MAX,
1221            num_groups: 2,
1222            group_width_reference: 0,
1223            group_width_bits: 2,
1224            group_length_reference: 2,
1225            group_length_increment: 1,
1226            true_length_last_group: 2,
1227            scaled_group_length_bits: 0,
1228            spatial_differencing: None,
1229        };
1230
1231        let values = unpack_complex(&[0x79, 0x90, 0x34], &params).unwrap();
1232        assert_eq!(values[0], 7.0);
1233        assert!(values[1].is_nan());
1234        assert_eq!(values[2], 9.0);
1235        assert!(values[3].is_nan());
1236    }
1237
1238    #[test]
1239    fn unpacks_complex_packing_applies_decimal_scale_to_reference_and_values() {
1240        let params = ComplexPackingParams {
1241            encoded_values: 2,
1242            reference_value: 10.0,
1243            binary_scale: 0,
1244            decimal_scale: 1,
1245            group_reference_bits: 4,
1246            original_field_type: 0,
1247            group_splitting_method: 1,
1248            missing_value_management: 0,
1249            primary_missing_substitute: u32::MAX,
1250            secondary_missing_substitute: u32::MAX,
1251            num_groups: 1,
1252            group_width_reference: 4,
1253            group_width_bits: 0,
1254            group_length_reference: 2,
1255            group_length_increment: 1,
1256            true_length_last_group: 2,
1257            scaled_group_length_bits: 0,
1258            spatial_differencing: None,
1259        };
1260
1261        let values = unpack_complex(&[0x10, 0x02], &params).unwrap();
1262        assert!((values[0] - 1.1).abs() < 1e-12);
1263        assert!((values[1] - 1.3).abs() < 1e-12);
1264    }
1265
1266    #[test]
1267    fn unpacks_complex_packing_with_second_order_spatial_differencing() {
1268        let params = ComplexPackingParams {
1269            encoded_values: 4,
1270            reference_value: 0.0,
1271            binary_scale: 0,
1272            decimal_scale: 0,
1273            group_reference_bits: 1,
1274            original_field_type: 0,
1275            group_splitting_method: 1,
1276            missing_value_management: 0,
1277            primary_missing_substitute: u32::MAX,
1278            secondary_missing_substitute: u32::MAX,
1279            num_groups: 1,
1280            group_width_reference: 1,
1281            group_width_bits: 0,
1282            group_length_reference: 4,
1283            group_length_increment: 1,
1284            true_length_last_group: 4,
1285            scaled_group_length_bits: 0,
1286            spatial_differencing: Some(SpatialDifferencingParams {
1287                order: 2,
1288                descriptor_octets: 2,
1289            }),
1290        };
1291
1292        let values =
1293            unpack_complex(&[0x00, 0x0A, 0x00, 0x0D, 0x00, 0x03, 0x00, 0x10], &params).unwrap();
1294        assert_eq!(values, vec![10.0, 13.0, 19.0, 29.0]);
1295    }
1296
1297    #[test]
1298    fn unpacks_complex_packing_with_spatial_differencing_and_missing_values() {
1299        let params = ComplexPackingParams {
1300            encoded_values: 4,
1301            reference_value: 0.0,
1302            binary_scale: 0,
1303            decimal_scale: 0,
1304            group_reference_bits: 1,
1305            original_field_type: 0,
1306            group_splitting_method: 1,
1307            missing_value_management: 1,
1308            primary_missing_substitute: u32::MAX,
1309            secondary_missing_substitute: u32::MAX,
1310            num_groups: 1,
1311            group_width_reference: 2,
1312            group_width_bits: 0,
1313            group_length_reference: 4,
1314            group_length_increment: 1,
1315            true_length_last_group: 4,
1316            scaled_group_length_bits: 0,
1317            spatial_differencing: Some(SpatialDifferencingParams {
1318                order: 1,
1319                descriptor_octets: 2,
1320            }),
1321        };
1322
1323        let values = unpack_complex(&[0x00, 0x0A, 0x00, 0x03, 0x00, 0x32], &params).unwrap();
1324        assert_eq!(values[0], 10.0);
1325        assert!(values[1].is_nan());
1326        assert_eq!(values[2], 13.0);
1327        assert_eq!(values[3], 18.0);
1328    }
1329}