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