1use 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
17pub 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
43pub 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
65pub 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
473pub 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(§ion_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
521pub 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 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 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 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 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, ¶ms.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 ¶ms.packing,
1115 output,
1116 ),
1117 (png::ColorType::Grayscale, png::BitDepth::Eight, 8) => {
1118 unpack_png_bytes(data, 1, num_values, ¶ms.packing, output)
1119 }
1120 (png::ColorType::Grayscale, png::BitDepth::Sixteen, 16) => {
1121 unpack_png_u16(data, num_values, ¶ms.packing, output)
1122 }
1123 (png::ColorType::Rgb, png::BitDepth::Eight, 24) => {
1124 unpack_png_bytes(data, 3, num_values, ¶ms.packing, output)
1125 }
1126 (png::ColorType::Rgba, png::BitDepth::Eight, 32) => {
1127 unpack_png_bytes(data, 4, num_values, ¶ms.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(&[], ¶ms, 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], ¶ms, 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(), ¶ms, 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], ¶ms, 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 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], ¶ms, 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], ¶ms).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], ¶ms).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], ¶ms).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], ¶ms).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}