1use std::vec::IntoIter;
2
3use crate::{
4 TryFromSlice as _,
5 context::{SectionBody, SubMessage},
6 decoder::{
7 bitmap::{BitmapDecodeIterator, dummy_bitmap_for_nonnullable_data},
8 complex::ComplexPackingDecoded,
9 simple::SimplePackingDecoder,
10 stream::NBitwiseIterator,
11 },
12 def::grib2::{DataRepresentationTemplate, Section5, SectionHeader},
13 error::*,
14 reader::Grib2Read,
15};
16
17pub struct Grib2SubmessageDecoder {
87 num_points_total: usize,
88 sect5_param: Section5,
89 sect6_bytes: Vec<u8>,
90 sect7_bytes: Vec<u8>,
91}
92
93impl Grib2SubmessageDecoder {
94 pub fn new(
99 num_points_total: usize,
100 sect5_bytes: Vec<u8>,
101 sect6_bytes: Vec<u8>,
102 sect7_bytes: Vec<u8>,
103 ) -> Result<Self, GribError> {
104 Self::check_section_slice(6, §6_bytes)?;
105 Self::check_section_slice(7, §7_bytes)?;
106 Self::new_from_checked_slices(num_points_total, sect5_bytes, sect6_bytes, sect7_bytes)
107 }
108
109 fn check_section_slice(sect_num: u8, bytes: &[u8]) -> Result<(), GribError> {
110 let header = SectionHeader::try_from_slice(bytes, &mut 0)
111 .map_err(|e| GribError::DecodeError(DecodeError::from(e)))?;
112 if header.sect_num != sect_num || header.len as usize != bytes.len() {
113 return Err(GribError::DecodeError(DecodeError::from(format!(
114 "invalid section {sect_num} slice"
115 ))));
116 }
117 Ok(())
118 }
119
120 fn new_from_checked_slices(
121 num_points_total: usize,
122 sect5_bytes: Vec<u8>,
123 sect6_bytes: Vec<u8>,
124 sect7_bytes: Vec<u8>,
125 ) -> Result<Self, GribError> {
126 let mut pos = 0;
127 let sect5_param = Section5::try_from_slice(§5_bytes, &mut pos)
128 .map_err(|e| GribError::DecodeError(DecodeError::from(e)))?;
129 let sect6_bytes = match sect6_bytes[5] {
130 0x00 => sect6_bytes,
131 0xff => {
132 let mut sect6_bytes = sect6_bytes;
133 sect6_bytes.append(&mut dummy_bitmap_for_nonnullable_data(num_points_total));
134 sect6_bytes
135 }
136 n => {
137 return Err(GribError::DecodeError(DecodeError::NotSupported(
138 "GRIB2 code table 6.0 (bit map indicator)",
139 n.into(),
140 )));
141 }
142 };
143
144 Ok(Self {
145 num_points_total,
146 sect5_param,
147 sect6_bytes,
148 sect7_bytes,
149 })
150 }
151
152 pub fn from<R: Grib2Read>(submessage: SubMessage<R>) -> Result<Self, GribError> {
154 let mut reader = submessage.9;
155 let sect5 = submessage.5.body;
156 let sect6 = submessage.6.body;
157 let sect7 = submessage.7.body;
158 let sect3_body = match submessage.3.body.body.as_ref() {
159 Some(SectionBody::Section3(b3)) => b3,
160 _ => return Err(GribError::InternalDataError),
161 };
162 let sect3_num_points = sect3_body.num_points() as usize;
163
164 Self::new_from_checked_slices(
165 sect3_num_points,
166 reader.read_sect_as_slice(sect5)?,
167 reader.read_sect_as_slice(sect6)?,
168 reader.read_sect_as_slice(sect7)?,
169 )
170 }
171
172 pub fn dispatch(
174 &self,
175 ) -> Result<Grib2DecodedValues<'_, impl Iterator<Item = f32> + '_>, GribError> {
176 let decoder = match &self.sect5_param.payload.template {
177 DataRepresentationTemplate::_5_0(template) => {
178 Grib2ValueIterator::SigSTNS(simple::Simple(self, template).iter()?)
179 }
180 DataRepresentationTemplate::_5_2(template) => {
181 Grib2ValueIterator::SigSC(complex::Complex(self, template).iter()?)
182 }
183 DataRepresentationTemplate::_5_3(template) => {
184 Grib2ValueIterator::SigSSCI(complex::ComplexSpatial(self, template).iter()?)
185 }
186 #[cfg(any(
187 feature = "jpeg2000-unpack-with-openjpeg",
188 feature = "jpeg2000-unpack-with-hayro"
189 ))]
190 DataRepresentationTemplate::_5_40(template) => {
191 Grib2ValueIterator::SigSIm(jpeg2000::Jpeg2000(self, template).iter()?)
192 }
193 #[cfg(feature = "png-unpack-with-png-crate")]
194 DataRepresentationTemplate::_5_41(template) => {
195 Grib2ValueIterator::SigSNV(png::Png(self, template).iter()?)
196 }
197 #[cfg(any(
198 feature = "ccsds-unpack-with-libaec",
199 feature = "ccsds-unpack-with-rust-aec"
200 ))]
201 DataRepresentationTemplate::_5_42(template) => {
202 Grib2ValueIterator::SigSNV(ccsds::Ccsds(self, template).iter()?)
203 }
204 DataRepresentationTemplate::_5_200(template) => {
205 Grib2ValueIterator::SigI(run_length::RunLength(self, template).iter()?)
206 }
207 #[allow(unreachable_patterns)]
208 _ => {
209 return Err(GribError::DecodeError(DecodeError::NotSupported(
210 "GRIB2 code table 5.0 (data representation template number)",
211 self.sect5_param.payload.template_num,
212 )));
213 }
214 };
215
216 let bitmap_slice = &self.sect6_bytes[6..];
217 bitmap::check_consistency(
218 self.num_points_total,
219 self.num_encoded_points(),
220 bitmap_slice,
221 )?;
222 let decoder =
223 BitmapDecodeIterator::new(bitmap_slice.iter(), decoder, self.num_points_total);
224 Ok(Grib2DecodedValues(decoder))
225 }
226
227 pub(crate) fn num_encoded_points(&self) -> usize {
228 self.sect5_param.payload.num_encoded_points as usize
229 }
230
231 pub(crate) fn sect7_payload(&self) -> &[u8] {
232 &self.sect7_bytes[5..]
233 }
234
235 pub fn section5(&self) -> &Section5 {
276 &self.sect5_param
277 }
278}
279
280pub(crate) fn orig_field_type_is_supported(orig_field_type: u8) -> Result<(), DecodeError> {
281 if orig_field_type != 0 {
282 return Err(DecodeError::NotSupported(
283 "GRIB2 code table 5.1 (type of original field values)",
284 orig_field_type.into(),
285 ));
286 }
287 Ok(())
288}
289
290pub struct Grib2DecodedValues<'b, I>(BitmapDecodeIterator<std::slice::Iter<'b, u8>, I>);
291
292impl<I> Iterator for Grib2DecodedValues<'_, I>
293where
294 I: Iterator<Item = f32>,
295{
296 type Item = f32;
297
298 fn next(&mut self) -> Option<Self::Item> {
299 let Self(inner) = self;
300 inner.next()
301 }
302
303 fn size_hint(&self) -> (usize, Option<usize>) {
304 let Self(inner) = self;
305 inner.size_hint()
306 }
307}
308
309enum Grib2ValueIterator<'d> {
310 SigSTNS(SimplePackingDecoder<std::iter::Take<NBitwiseIterator<&'d [u8]>>>),
311 SigSC(SimplePackingDecoder<ComplexPackingDecoded<'d>>),
312 SigSSCI(
313 SimplePackingDecoder<
314 complex::SpatialDifferencingDecodeIterator<ComplexPackingDecoded<'d>, IntoIter<i32>>,
315 >,
316 ),
317 #[allow(dead_code)]
318 SigSI(SimplePackingDecoder<IntoIter<i32>>),
319 #[cfg(any(
320 feature = "jpeg2000-unpack-with-openjpeg",
321 feature = "jpeg2000-unpack-with-hayro"
322 ))]
323 SigSIm(SimplePackingDecoder<self::jpeg2000::ImageIntoIter>),
324 #[allow(dead_code)]
325 SigSNV(SimplePackingDecoder<NBitwiseIterator<Vec<u8>>>),
326 SigI(IntoIter<f32>),
327}
328
329impl<'d> Iterator for Grib2ValueIterator<'d> {
330 type Item = f32;
331
332 fn next(&mut self) -> Option<Self::Item> {
333 match self {
334 Self::SigSTNS(inner) => inner.next(),
335 Self::SigSC(inner) => inner.next(),
336 Self::SigSSCI(inner) => inner.next(),
337 Self::SigSI(inner) => inner.next(),
338 #[cfg(any(
339 feature = "jpeg2000-unpack-with-openjpeg",
340 feature = "jpeg2000-unpack-with-hayro"
341 ))]
342 Self::SigSIm(inner) => inner.next(),
343 Self::SigSNV(inner) => inner.next(),
344 Self::SigI(inner) => inner.next(),
345 }
346 }
347
348 fn size_hint(&self) -> (usize, Option<usize>) {
349 match self {
350 Self::SigSTNS(inner) => inner.size_hint(),
351 Self::SigSC(inner) => inner.size_hint(),
352 Self::SigSSCI(inner) => inner.size_hint(),
353 Self::SigSI(inner) => inner.size_hint(),
354 #[cfg(any(
355 feature = "jpeg2000-unpack-with-openjpeg",
356 feature = "jpeg2000-unpack-with-hayro"
357 ))]
358 Self::SigSIm(inner) => inner.size_hint(),
359 Self::SigSNV(inner) => inner.size_hint(),
360 Self::SigI(inner) => inner.size_hint(),
361 }
362 }
363}
364
365#[derive(Debug, Clone, PartialEq, Eq, Hash)]
366#[non_exhaustive]
367pub enum DecodeError {
368 NotSupported(&'static str, u16),
369 LengthMismatch,
370 UnclassifiedError(String),
371}
372
373impl From<String> for DecodeError {
374 fn from(value: String) -> Self {
375 Self::UnclassifiedError(value)
376 }
377}
378
379impl From<&str> for DecodeError {
380 fn from(value: &str) -> Self {
381 Self::UnclassifiedError(value.to_owned())
382 }
383}
384
385pub(crate) trait Grib2GpvUnpack {
386 type Iter<'a>: Iterator<Item = f32>
387 where
388 Self: 'a;
389
390 fn iter<'a>(&'a self) -> Result<Self::Iter<'a>, DecodeError>;
391}
392
393mod bitmap;
394#[cfg(any(
395 feature = "ccsds-unpack-with-libaec",
396 feature = "ccsds-unpack-with-rust-aec"
397))]
398mod ccsds;
399mod complex;
400mod helpers;
401#[cfg(any(
402 feature = "jpeg2000-unpack-with-openjpeg",
403 feature = "jpeg2000-unpack-with-hayro"
404))]
405mod jpeg2000;
406#[cfg(feature = "png-unpack-with-png-crate")]
407mod png;
408mod run_length;
409mod simple;
410mod stream;
411#[cfg(test)]
412mod tests;