doris_rs/header/
parsing.rs1use crate::{
2 error::ParsingError,
3 header::{Antenna, Header, Receiver, Version},
4 observable::Observable,
5 prelude::{Duration, Epoch, TimeScale, COSPAR},
6 station::GroundStation,
7 Comments,
8};
9
10use std::{
11 collections::HashMap,
12 io::{BufRead, BufReader, Read},
13 str::FromStr,
14};
15
16impl Header {
17 pub fn parse<R: Read>(reader: &mut BufReader<R>) -> Result<Self, ParsingError> {
19 let mut version = Version::default();
20
21 let mut satellite = String::with_capacity(16);
22 let mut program = Option::<String>::None;
23 let mut run_by = Option::<String>::None;
24 let mut date = Option::<String>::None;
25 let mut observer = Option::<String>::None;
26 let mut agency = Option::<String>::None;
27 let mut license = Option::<String>::None;
28 let mut doi = Option::<String>::None;
29 let mut receiver = Option::<Receiver>::None;
30 let mut antenna = Option::<Antenna>::None;
31 let mut cospar = Option::<COSPAR>::None;
32 let mut l1_l2_date_offset = Duration::default();
33 let mut ground_stations = Vec::with_capacity(8);
34 let mut scaling_factors = HashMap::new();
35 let mut time_of_first_observation = Option::<Epoch>::None;
36 let mut time_of_last_observation = Option::<Epoch>::None;
37
38 let mut observables = Vec::<Observable>::with_capacity(8);
39 let mut observables_continuation = false;
40
41 let mut comments = Comments::default();
42
43 for line in reader.lines() {
44 if line.is_err() {
45 continue;
47 }
48
49 let line = line.unwrap();
50
51 if line.len() < 60 {
52 continue;
54 }
55
56 let (content, marker) = line.split_at(60);
57 let marker = marker.trim();
58
59 if marker.eq("END OF HEADER") {
60 break;
62 }
63
64 if marker.eq("COMMENT") {
65 comments.push(content.trim().to_string());
67 continue;
68 } else if marker.eq("RINEX VERSION / TYPE") {
69 let (vers, rem) = line.split_at(20);
70 let (type_str, rem) = rem.split_at(20);
71 let (constell_str, _) = rem.split_at(20);
72
73 let vers = vers.trim();
74 let type_str = type_str.trim();
75 let constell_str = constell_str.trim();
76
77 if !type_str.eq("O") {
78 return Err(ParsingError::InvalidDoris);
79 }
80
81 if !constell_str.eq("D") {
82 return Err(ParsingError::InvalidDoris);
83 }
84
85 version = Version::from_str(vers).or(Err(ParsingError::Version))?;
87 } else if marker.eq("PGM / RUN BY / DATE") {
88 let (pgm, rem) = line.split_at(20);
89 let pgm = pgm.trim();
90 if pgm.len() > 0 {
91 program = Some(pgm.to_string());
92 }
93
94 let (runby, rem) = rem.split_at(20);
95
96 let runby = runby.trim();
97 if runby.len() > 0 {
98 run_by = Some(runby.to_string());
99 }
100
101 let date_str = rem.split_at(20).0.trim();
102 if date_str.len() > 0 {
103 date = Some(date_str.to_string());
104 }
105 } else if marker.eq("SATELLITE NAME") {
106 let name = content.split_at(20).0.trim();
107 satellite = name.to_string();
108 } else if marker.eq("OBSERVER / AGENCY") {
109 let (obs, ag) = content.split_at(20);
110 let obs = obs.trim();
111 let ag = ag.trim();
112
113 if obs.len() > 0 {
114 observer = Some(obs.to_string());
115 }
116
117 if ag.len() > 0 {
118 agency = Some(ag.to_string());
119 }
120 } else if marker.eq("REC # / TYPE / VERS") {
121 if let Ok(rx) = Receiver::from_str(content) {
122 receiver = Some(rx);
123 }
124 } else if marker.eq("SYS / SCALE FACTOR") {
125 } else if marker.eq("LICENSE OF USE") {
145 let lic = content.split_at(40).0.trim();
146 if lic.len() > 0 {
147 license = Some(lic.to_string());
148 }
149 } else if marker.eq("DOI") {
150 let content = content.split_at(40).0.trim();
151
152 if content.len() > 0 {
153 doi = Some(content.to_string());
154 }
155 } else if marker.eq("ANT # / TYPE") {
156 let (sn, rem) = content.split_at(20);
157 let (model, _) = rem.split_at(20);
158
159 antenna = Some(
160 Antenna::default()
161 .with_model(model.trim())
162 .with_serial_number(sn.trim()),
163 );
164 } else if marker.eq("# OF STATIONS") {
165 } else if marker.eq("TIME OF FIRST OBS") {
166 time_of_first_observation = Some(Self::parse_time_of_obs(content)?);
167 } else if marker.eq("TIME OF LAST OBS") {
168 time_of_last_observation = Some(Self::parse_time_of_obs(content)?);
169 } else if marker.eq("SYS / # / OBS TYPES") {
170 if observables_continuation {
171 for item in content.split_ascii_whitespace() {
172 if let Ok(observable) = Observable::from_str(item) {
173 observables.push(observable);
174 }
175 }
176 } else {
177 Self::parse_observables(content, &mut observables);
178 observables_continuation = true;
179 }
180 } else if marker.eq("COSPAR NUMBER") {
181 cospar = Some(COSPAR::from_str(content.trim())?);
182 } else if marker.eq("L2 / L1 DATE OFFSET") {
183 let content = content[1..].trim();
185
186 let time_offset_us = content
187 .parse::<f64>()
188 .or(Err(ParsingError::DorisL1L2DateOffset))?;
189
190 l1_l2_date_offset = Duration::from_microseconds(time_offset_us);
191 } else if marker.eq("STATION REFERENCE") {
192 let station = GroundStation::from_str(content.trim())?;
194 ground_stations.push(station);
195 }
196 }
197
198 Ok(Header {
199 version,
200 comments,
201 program,
202 run_by,
203 date,
204 agency,
205 observer,
206 license,
207 doi,
208 receiver,
209 antenna,
210 cospar,
211 satellite,
212 scaling_factors,
213 l1_l2_date_offset,
214 observables,
215 ground_stations,
216 time_of_first_observation,
217 time_of_last_observation,
218 })
219 }
220
221 fn parse_observables(line: &str, observables: &mut Vec<Observable>) {
222 let items = line.split_at(6).1;
223 for item in items.split_ascii_whitespace() {
224 if let Ok(observable) = Observable::from_str(item) {
225 observables.push(observable);
226 }
227 }
228 }
229
230 fn parse_time_of_obs(content: &str) -> Result<Epoch, ParsingError> {
231 let (_, rem) = content.split_at(2);
232 let (y, rem) = rem.split_at(4);
233 let (m, rem) = rem.split_at(6);
234 let (d, rem) = rem.split_at(6);
235 let (hh, rem) = rem.split_at(6);
236 let (mm, rem) = rem.split_at(6);
237 let (ss, rem) = rem.split_at(5);
238 let (_dot, rem) = rem.split_at(1);
239 let (ns, rem) = rem.split_at(8);
240
241 let mut y = y
243 .trim()
244 .parse::<u32>()
245 .map_err(|_| ParsingError::EpochFormat)?;
246
247 if y >= 79 && y <= 99 {
249 y += 1900;
250 } else if y < 79 {
251 y += 2000;
252 }
253
254 let m = m
255 .trim()
256 .parse::<u8>()
257 .map_err(|_| ParsingError::EpochFormat)?;
258
259 let d = d
260 .trim()
261 .parse::<u8>()
262 .map_err(|_| ParsingError::EpochFormat)?;
263
264 let hh = hh
265 .trim()
266 .parse::<u8>()
267 .map_err(|_| ParsingError::EpochFormat)?;
268
269 let mm = mm
270 .trim()
271 .parse::<u8>()
272 .map_err(|_| ParsingError::EpochFormat)?;
273
274 let ss = ss
275 .trim()
276 .parse::<u8>()
277 .map_err(|_| ParsingError::EpochFormat)?;
278
279 let ns = ns
280 .trim()
281 .parse::<u32>()
282 .map_err(|_| ParsingError::EpochFormat)?;
283
284 let mut ts = TimeScale::TAI;
290 let rem = rem.trim();
291
292 if !rem.is_empty() && rem != "DOR" {
297 ts = TimeScale::from_str(rem.trim())?;
298 }
299
300 Epoch::from_str(&format!(
301 "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:08} {}",
302 y, m, d, hh, mm, ss, ns, ts
303 ))
304 .map_err(|_| ParsingError::EpochFormat)
305 }
306}
307
308#[cfg(test)]
309mod test {
310 use crate::prelude::{Epoch, Header};
311 use std::str::FromStr;
312
313 #[test]
314 fn parse_time_of_obs() {
315 let content = " 2021 12 21 0 0 0.0000000 GPS";
316 let parsed = Header::parse_time_of_obs(&content).unwrap();
317 assert_eq!(parsed, Epoch::from_str("2021-12-21T00:00:00 GPST").unwrap());
318
319 let content = " 1995 01 01 00 00 00.000000 ";
320 let parsed = Header::parse_time_of_obs(&content).unwrap();
321 assert_eq!(parsed, Epoch::from_str("1995-01-01T00:00:00 TAI").unwrap());
322 }
323}