1use serde::{Deserialize, Serialize};
29
30use super::{Grib2Error, be_i16, be_u32, malformed, need, truncated};
31
32#[non_exhaustive]
34#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
35pub struct ComplexPacking {
36 pub reference: f32,
38 pub binary_scale: i16,
40 pub decimal_scale: i16,
42 pub count: u32,
44 pub group_reference_bits: u8,
46 pub missing_values: u8,
49 pub groups: u32,
51 pub width_reference: u8,
53 pub width_bits: u8,
55 pub length_reference: u32,
57 pub length_increment: u8,
59 pub last_length: u32,
61 pub length_bits: u8,
63 pub spatial_differencing: Option<SpatialDifferencing>,
65}
66
67#[non_exhaustive]
69#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
70pub struct SpatialDifferencing {
71 pub order: u8,
73 pub octets: u8,
75}
76
77impl ComplexPacking {
78 #[must_use]
80 #[allow(
81 clippy::cast_precision_loss,
82 reason = "a valid field's integers are far below 2^53; a hostile one's only lose digits"
83 )]
84 pub fn unpack(&self, h: i64) -> f64 {
85 super::unpack(
86 self.reference,
87 self.binary_scale,
88 self.decimal_scale,
89 h as f64,
90 )
91 }
92}
93
94pub(super) fn read(s: &[u8], template: u16, message: usize) -> Result<ComplexPacking, Grib2Error> {
96 let s = need(s, 47, "data template 5.2", message)?;
97 if s[20] > 1 {
99 return Err(Grib2Error::Unsupported {
100 message,
101 what: "type of original field values",
102 value: s[20].into(),
103 });
104 }
105 let reference = f32::from_bits(be_u32(&s[11..15]));
106 if !reference.is_finite() {
107 return Err(malformed(message, "the reference value is not finite"));
108 }
109 if s[21] != 1 {
112 return Err(Grib2Error::Unsupported {
113 message,
114 what: "group splitting method",
115 value: s[21].into(),
116 });
117 }
118 let missing_values = s[22];
119 if missing_values > 2 {
120 return Err(Grib2Error::Unsupported {
121 message,
122 what: "missing value management",
123 value: missing_values.into(),
124 });
125 }
126 let spatial_differencing = if template == 3 {
127 let s = need(s, 49, "data template 5.3", message)?;
128 let (order, octets) = (s[47], s[48]);
129 if !(1..=2).contains(&order) {
130 return Err(Grib2Error::Unsupported {
131 message,
132 what: "order of spatial differencing",
133 value: order.into(),
134 });
135 }
136 if !(1..=8).contains(&octets) {
137 return Err(Grib2Error::Unsupported {
138 message,
139 what: "bytes per extra descriptor",
140 value: octets.into(),
141 });
142 }
143 Some(SpatialDifferencing { order, octets })
144 } else {
145 None
146 };
147 let packing = ComplexPacking {
148 reference,
149 binary_scale: be_i16(&s[15..17]),
150 decimal_scale: be_i16(&s[17..19]),
151 count: be_u32(&s[5..9]),
152 group_reference_bits: s[19],
153 missing_values,
154 groups: be_u32(&s[31..35]),
155 width_reference: s[35],
156 width_bits: s[36],
157 length_reference: be_u32(&s[37..41]),
158 length_increment: s[41],
159 last_length: be_u32(&s[42..46]),
160 length_bits: s[46],
161 spatial_differencing,
162 };
163 for (what, bits) in [
164 ("bits per group reference", packing.group_reference_bits),
165 ("bits per group width", packing.width_bits),
166 ("bits per group length", packing.length_bits),
167 ] {
168 if bits > 32 {
169 return Err(Grib2Error::Unsupported {
170 message,
171 what,
172 value: bits.into(),
173 });
174 }
175 }
176 if missing_values == 2 && packing.group_reference_bits == 0 {
177 return Err(Grib2Error::Unsupported {
180 message,
181 what: "secondary missing values with 0-bit group references, management",
182 value: missing_values.into(),
183 });
184 }
185 Ok(packing)
186}
187
188#[derive(Debug, Clone, Copy, PartialEq)]
192pub(super) struct Layout {
193 packing: ComplexPacking,
194 first: [i64; 2],
196 minimum: i64,
197 references: u64,
198 widths: u64,
199 lengths: u64,
200 values: u64,
201}
202
203pub(super) fn layout(
211 p: &ComplexPacking,
212 data: &[u8],
213 message: usize,
214) -> Result<Layout, Grib2Error> {
215 let have = data.len() as u64 * 8;
216 let groups = u64::from(p.groups);
217 let count = u64::from(p.count);
218 if groups == 0 && count > 0 {
219 return Err(Grib2Error::Unsupported {
222 message,
223 what: "complex packing with no groups, values",
224 value: count,
225 });
226 }
227 if groups > count {
228 return Err(malformed(
229 message,
230 format!("{groups} groups for {count} packed values"),
231 ));
232 }
233 let (mut first, mut minimum, mut at) = ([0; 2], 0, 0_u64);
234 if let Some(d) = p.spatial_differencing {
235 let octets = usize::from(d.octets);
236 let len = octets * (usize::from(d.order) + 1);
237 if data.len() < len {
238 return Err(truncated(message, "the extra descriptors", len, data.len()));
239 }
240 let field = |k: usize| &data[k * octets..(k + 1) * octets];
241 for (k, slot) in first.iter_mut().take(usize::from(d.order)).enumerate() {
242 if field(k)[0] & 0x80 != 0 {
246 return Err(malformed(
247 message,
248 "a first value has its top bit set, which decoders read two ways",
249 ));
250 }
251 *slot = sign_magnitude(field(k));
252 }
253 minimum = sign_magnitude(field(usize::from(d.order)));
254 at = len as u64 * 8;
255 }
256 let list = |at: u64, bits: u8| at + (groups * u64::from(bits)).div_ceil(8) * 8;
257 let references = at;
258 let widths = list(references, p.group_reference_bits);
259 let lengths = list(widths, p.width_bits);
260 let values = list(lengths, p.length_bits);
261 if values > have {
262 return Err(truncated(
263 message,
264 "the group descriptors",
265 values.div_ceil(8),
266 data.len(),
267 ));
268 }
269 let wide = |width: u64| Grib2Error::Unsupported {
270 message,
271 what: "group width, bits",
272 value: width,
273 };
274 let (mut total, mut bits) = (0_u64, 0_u64);
275 if p.width_bits == 0 && p.length_bits == 0 {
276 let width = u64::from(p.width_reference);
278 if width > 32 {
279 return Err(wide(width));
280 }
281 total = groups.checked_sub(1).map_or(0, |g| {
284 g * u64::from(p.length_reference) + u64::from(p.last_length)
285 });
286 bits = if total <= count { total * width } else { 0 };
287 } else {
288 for k in 0..groups {
289 let (width, length) = group(p, data, widths, lengths, k);
290 if width > 32 {
291 return Err(wide(width));
292 }
293 total += length;
294 bits += length * width;
297 if total > count {
298 break;
299 }
300 }
301 }
302 if total != count {
303 return Err(malformed(
304 message,
305 format!("the groups hold {total} values but section 5 packs {count}"),
306 ));
307 }
308 if values + bits > have {
309 return Err(truncated(
310 message,
311 "the packed values",
312 (values + bits).div_ceil(8),
313 data.len(),
314 ));
315 }
316 Ok(Layout {
317 packing: *p,
318 first,
319 minimum,
320 references,
321 widths,
322 lengths,
323 values,
324 })
325}
326
327fn group(p: &ComplexPacking, data: &[u8], widths: u64, lengths: u64, k: u64) -> (u64, u64) {
329 let wb = u64::from(p.width_bits);
330 let width = u64::from(p.width_reference) + bits(data, widths + k * wb, p.width_bits);
331 let length = if k + 1 == u64::from(p.groups) {
332 u64::from(p.last_length)
333 } else {
334 let lb = u64::from(p.length_bits);
335 u64::from(p.length_reference)
336 + bits(data, lengths + k * lb, p.length_bits) * u64::from(p.length_increment)
337 };
338 (width, length)
339}
340
341pub(super) fn bits(data: &[u8], start: u64, n: u8) -> u64 {
344 if n == 0 {
345 return 0;
346 }
347 let byte = usize::try_from(start / 8).unwrap_or(usize::MAX);
348 let mut word = [0_u8; 8];
349 let rest = data.get(byte..).unwrap_or(&[]);
350 let take = rest.len().min(8);
351 word[..take].copy_from_slice(&rest[..take]);
352 (u64::from_be_bytes(word) << (start % 8)) >> (64 - u32::from(n))
354}
355
356fn sign_magnitude(b: &[u8]) -> i64 {
358 let mut raw: u64 = 0;
359 for &byte in b {
360 raw = (raw << 8) | u64::from(byte);
361 }
362 let top = 8 * b.len() as u32 - 1;
363 let magnitude = i64::try_from(raw & ((1_u64 << top) - 1)).unwrap_or(i64::MAX);
365 if raw >> top & 1 == 1 {
366 -magnitude
367 } else {
368 magnitude
369 }
370}
371
372pub(super) fn decode(
379 layout: &Layout,
380 data: &[u8],
381 end: u64,
382 message: usize,
383 mut sink: impl FnMut(u64, Option<f64>),
384) -> Result<(), Grib2Error> {
385 let p = &layout.packing;
386 let order = p.spatial_differencing.map_or(0, |d| d.order);
387 let rb = p.group_reference_bits;
388 let all_ones = |bits: u64| (1_u64 << bits) - 1;
389 let overflow = || malformed(message, "the spatial differences overflow 64 bits");
390 let (mut position, mut at, mut present) = (0_u64, layout.values, 0_u64);
391 let (mut previous, mut before) = (0_i64, 0_i64);
392 for k in 0..u64::from(p.groups) {
393 if position >= end {
394 break;
395 }
396 let (width, length) = group(p, data, layout.widths, layout.lengths, k);
397 let reference = bits(data, layout.references + k * u64::from(rb), rb);
398 for _ in 0..length {
399 if position >= end {
400 return Ok(());
401 }
402 let w = u8::try_from(width).unwrap_or(32);
404 let (x, missing) = if width == 0 {
405 let r = u64::from(rb);
406 (
407 reference,
408 (p.missing_values >= 1 && reference == all_ones(r))
409 || (p.missing_values == 2 && reference == all_ones(r) - 1),
410 )
411 } else {
412 let x2 = bits(data, at, w);
413 at += width;
414 (
415 reference + x2,
416 (p.missing_values >= 1 && x2 == all_ones(width))
417 || (p.missing_values == 2 && x2 == all_ones(width) - 1),
418 )
419 };
420 if missing {
421 sink(position, None);
422 position += 1;
423 continue;
424 }
425 let z = i64::try_from(x).unwrap_or(i64::MAX);
427 let h = match (order, present) {
428 (0, _) => z,
429 (_, 0) => layout.first[0],
430 (2, 1) => layout.first[1],
431 (1, _) => z
432 .checked_add(layout.minimum)
433 .and_then(|v| v.checked_add(previous))
434 .ok_or_else(overflow)?,
435 _ => z
436 .checked_add(layout.minimum)
437 .and_then(|v| v.checked_add(previous.checked_mul(2)?))
438 .and_then(|v| v.checked_sub(before))
439 .ok_or_else(overflow)?,
440 };
441 before = previous;
442 previous = h;
443 present += 1;
444 sink(position, Some(p.unpack(h)));
445 position += 1;
446 }
447 }
448 Ok(())
449}