1use crate::data::{decode_payload, DataRepresentation};
4use crate::error::{Error, Result};
5use crate::indicator::grib1_section4_length;
6use crate::sections::SectionRef;
7
8use grib_core::binary::read_u24_be;
9pub use grib_core::grib1::{BinaryDataSection, GridDescription, ProductDefinition};
10
11pub fn bitmap_payload(section_bytes: &[u8]) -> Result<Option<&[u8]>> {
12 let indicator = bitmap_table_reference(section_bytes)?;
13 if indicator == 0 {
14 Ok(Some(§ion_bytes[6..]))
15 } else {
16 Err(Error::UnsupportedBitmapIndicator(indicator))
17 }
18}
19
20pub fn bitmap_table_reference(section_bytes: &[u8]) -> Result<u16> {
21 if section_bytes.len() < 6 {
22 return Err(Error::InvalidSection {
23 section: 3,
24 reason: format!("expected at least 6 bytes, got {}", section_bytes.len()),
25 });
26 }
27 Ok(u16::from_be_bytes(section_bytes[4..6].try_into().unwrap()))
28}
29
30pub fn decode_simple_field(
31 data_section: &[u8],
32 representation: &DataRepresentation,
33 bitmap_section: Option<&[u8]>,
34 num_grid_points: usize,
35) -> Result<Vec<f64>> {
36 decode_payload(
37 data_section,
38 representation,
39 bitmap_section,
40 num_grid_points,
41 )
42}
43
44pub fn parse_message_sections(message_bytes: &[u8]) -> Result<Grib1Sections> {
45 if message_bytes.len() < 8 + 28 + 11 + 4 {
46 return Err(Error::InvalidMessage(format!(
47 "GRIB1 message too short: {} bytes",
48 message_bytes.len()
49 )));
50 }
51
52 let payload_limit = message_bytes.len() - 4;
53 let pds = parse_section(message_bytes, 8, 1, payload_limit)?;
54 let pds_bytes = &message_bytes[pds.offset..pds.offset + pds.length];
55 let product = ProductDefinition::parse(pds_bytes)?;
56
57 let mut cursor = pds.offset + pds.length;
58 let grid = if product.has_grid_definition {
59 let section_ref = parse_section(message_bytes, cursor, 2, payload_limit)?;
60 cursor += section_ref.length;
61 Some(section_ref)
62 } else {
63 None
64 };
65
66 let bitmap = if product.has_bitmap {
67 let section_ref = parse_section(message_bytes, cursor, 3, payload_limit)?;
68 cursor += section_ref.length;
69 Some(section_ref)
70 } else {
71 None
72 };
73
74 let data_length = grib1_section4_length(message_bytes, cursor).ok_or(Error::Truncated {
75 offset: cursor as u64,
76 })?;
77 let data = parse_section_with_length(cursor, data_length, 4, payload_limit)?;
78 if data.offset + data.length != payload_limit {
79 return Err(Error::InvalidMessage(
80 "GRIB1 message contains trailing bytes before end marker".into(),
81 ));
82 }
83
84 Ok(Grib1Sections {
85 product,
86 pds,
87 grid,
88 bitmap,
89 data,
90 })
91}
92
93#[derive(Debug, Clone)]
94pub struct Grib1Sections {
95 pub product: ProductDefinition,
96 pub pds: SectionRef,
97 pub grid: Option<SectionRef>,
98 pub bitmap: Option<SectionRef>,
99 pub data: SectionRef,
100}
101
102fn parse_section(
103 message_bytes: &[u8],
104 offset: usize,
105 number: u8,
106 payload_limit: usize,
107) -> Result<SectionRef> {
108 let length_bytes = message_bytes
109 .get(offset..offset + 3)
110 .ok_or(Error::Truncated {
111 offset: offset as u64,
112 })?;
113 let length = read_u24_be(length_bytes).ok_or(Error::Truncated {
114 offset: offset as u64,
115 })? as usize;
116 parse_section_with_length(offset, length, number, payload_limit)
117}
118
119fn parse_section_with_length(
120 offset: usize,
121 length: usize,
122 number: u8,
123 payload_limit: usize,
124) -> Result<SectionRef> {
125 if length < 3 {
126 return Err(Error::InvalidSection {
127 section: number,
128 reason: format!("section length {length} is smaller than the 3-byte header"),
129 });
130 }
131
132 let end = offset
133 .checked_add(length)
134 .ok_or_else(|| Error::InvalidMessage("GRIB1 section length overflow".into()))?;
135 if end > payload_limit {
136 return Err(Error::Truncated {
137 offset: offset as u64,
138 });
139 }
140
141 Ok(section(number, offset, length))
142}
143
144fn section(number: u8, offset: usize, length: usize) -> SectionRef {
145 SectionRef {
146 number,
147 offset,
148 length,
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::{bitmap_payload, bitmap_table_reference, parse_message_sections};
155 use crate::error::Error;
156
157 #[test]
158 fn parses_minimal_section_layout() {
159 let mut message = Vec::new();
160 message.extend_from_slice(b"GRIB");
161 message.extend_from_slice(&[0, 0, 64, 1]);
162 let mut pds = vec![0u8; 28];
163 pds[..3].copy_from_slice(&[0, 0, 28]);
164 pds[7] = 0b1000_0000;
165 pds[12] = 26;
166 pds[13] = 3;
167 pds[14] = 20;
168 pds[15] = 12;
169 pds[24] = 21;
170 message.extend_from_slice(&pds);
171 let mut gds = vec![0u8; 32];
172 gds[..3].copy_from_slice(&[0, 0, 32]);
173 message.extend_from_slice(&gds);
174 let mut bds = vec![0u8; 12];
175 bds[..3].copy_from_slice(&[0, 0, 12]);
176 message.extend_from_slice(&bds);
177 message.extend_from_slice(b"7777");
178
179 let sections = parse_message_sections(&message).unwrap();
180 assert!(sections.grid.is_some());
181 assert!(sections.bitmap.is_none());
182 assert_eq!(sections.data.length, 12);
183 }
184
185 #[test]
186 fn resolves_large_message_section4_length_from_message_boundary() {
187 let mut message = Vec::new();
188 message.extend_from_slice(b"GRIB");
189 message.extend_from_slice(&[0x80, 0, 1, 1]);
190 let mut pds = vec![0u8; 28];
191 pds[..3].copy_from_slice(&[0, 0, 28]);
192 pds[7] = 0b1000_0000;
193 pds[12] = 26;
194 pds[13] = 3;
195 pds[14] = 20;
196 pds[15] = 12;
197 pds[24] = 21;
198 message.extend_from_slice(&pds);
199 let mut gds = vec![0u8; 32];
200 gds[..3].copy_from_slice(&[0, 0, 32]);
201 message.extend_from_slice(&gds);
202 let mut bds = vec![0u8; 12];
203 bds[..3].copy_from_slice(&[0, 0, 40]);
205 message.extend_from_slice(&bds);
206 message.extend_from_slice(b"7777");
207
208 let sections = parse_message_sections(&message).unwrap();
209 assert_eq!(sections.data.offset, 68);
210 assert_eq!(sections.data.length, 12);
211 }
212
213 #[test]
214 fn rejects_section_length_beyond_message_boundary() {
215 let mut message = Vec::new();
216 message.extend_from_slice(b"GRIB");
217 message.extend_from_slice(&[0, 0, 64, 1]);
218 let mut pds = vec![0u8; 28];
219 pds[..3].copy_from_slice(&[0, 0, 28]);
220 pds[7] = 0b1000_0000;
221 pds[12] = 26;
222 pds[13] = 3;
223 pds[14] = 20;
224 pds[15] = 12;
225 pds[24] = 21;
226 message.extend_from_slice(&pds);
227 let mut gds = vec![0u8; 32];
228 gds[..3].copy_from_slice(&[0, 0, 250]);
229 message.extend_from_slice(&gds);
230 let mut bds = vec![0u8; 12];
231 bds[..3].copy_from_slice(&[0, 0, 12]);
232 message.extend_from_slice(&bds);
233 message.extend_from_slice(b"7777");
234
235 assert!(parse_message_sections(&message).is_err());
236 }
237
238 #[test]
239 fn reports_predefined_bitmap_indicator() {
240 assert_eq!(bitmap_table_reference(&[0, 0, 6, 0, 1, 44]).unwrap(), 300);
241
242 let err = bitmap_payload(&[0, 0, 6, 0, 1, 44]).unwrap_err();
243 assert!(matches!(err, Error::UnsupportedBitmapIndicator(300)));
244 }
245}