dis_rs/common/
parser.rs

1use crate::acknowledge_r::parser::acknowledge_r_body;
2use crate::action_request_r::parser::action_request_r_body;
3use crate::action_response_r::parser::action_response_r_body;
4use crate::aggregate_state::parser::aggregate_state_body;
5use crate::comment_r::parser::comment_r_body;
6use crate::common::acknowledge::parser::acknowledge_body;
7use crate::common::action_request::parser::action_request_body;
8use crate::common::action_response::parser::action_response_body;
9use crate::common::attribute::parser::attribute_body;
10use crate::common::collision::parser::collision_body;
11use crate::common::collision_elastic::parser::collision_elastic_body;
12use crate::common::comment::parser::comment_body;
13use crate::common::create_entity::parser::create_entity_body;
14use crate::common::data::parser::data_body;
15use crate::common::data_query::parser::data_query_body;
16use crate::common::designator::parser::designator_body;
17use crate::common::detonation::parser::detonation_body;
18use crate::common::electromagnetic_emission::parser::emission_body;
19use crate::common::entity_state::parser::entity_state_body;
20use crate::common::entity_state_update::parser::entity_state_update_body;
21use crate::common::errors::DisError;
22use crate::common::event_report::parser::event_report_body;
23use crate::common::fire::parser::fire_body;
24use crate::common::iff::parser::iff_body;
25use crate::common::model::{
26    length_padded_to_num, ArticulatedPart, AttachedPart, BeamData, ClockTime, DatumSpecification,
27    DescriptorRecord, EntityAssociationParameter, EntityId, EntityType, EntityTypeParameter,
28    EventId, FixedDatum, Location, MunitionDescriptor, Orientation, Pdu, PduBody, PduHeader,
29    SeparationParameter, SimulationAddress, VariableDatum, VariableParameter, VectorF32,
30};
31use crate::common::other::parser::other_body;
32use crate::common::receiver::parser::receiver_body;
33use crate::common::remove_entity::parser::remove_entity_body;
34use crate::common::set_data::parser::set_data_body;
35use crate::common::signal::parser::signal_body;
36use crate::common::start_resume::parser::start_resume_body;
37use crate::common::stop_freeze::parser::stop_freeze_body;
38use crate::common::transmitter::parser::transmitter_body;
39use crate::constants::{
40    EIGHT_OCTETS, FIVE_LEAST_SIGNIFICANT_BITS, ONE_BYTE_IN_BITS, PDU_HEADER_LEN_BYTES,
41};
42use crate::create_entity_r::parser::create_entity_r_body;
43use crate::data_query_r::parser::data_query_r_body;
44use crate::data_r::parser::data_r_body;
45use crate::enumerations::{
46    ArticulatedPartsTypeClass, ArticulatedPartsTypeMetric, AttachedPartDetachedIndicator,
47    AttachedParts, ChangeIndicator, EntityAssociationAssociationStatus,
48    EntityAssociationGroupMemberType, EntityAssociationPhysicalAssociationType,
49    EntityAssociationPhysicalConnectionType, SeparationPreEntityIndicator,
50    SeparationReasonForSeparation, VariableParameterRecordType,
51};
52use crate::enumerations::{
53    Country, DetonationTypeIndicator, EntityKind, ExplosiveMaterialCategories, FireTypeIndicator,
54    MunitionDescriptorFuse, MunitionDescriptorWarhead, PduType, PlatformDomain, ProtocolFamily,
55    ProtocolVersion, StationName, VariableRecordType,
56};
57use crate::event_report_r::parser::event_report_r_body;
58use crate::is_group_of::parser::is_group_of_body;
59use crate::is_part_of::parser::is_part_of_body;
60use crate::model::{RecordSet, RecordSpecification, SupplyQuantity};
61use crate::record_query_r::parser::record_query_r_body;
62use crate::record_r::parser::record_r_body;
63use crate::remove_entity_r::parser::remove_entity_r_body;
64use crate::repair_complete::parser::repair_complete_body;
65use crate::repair_response::parser::repair_response_body;
66use crate::resupply_cancel::parser::resupply_cancel_body;
67use crate::resupply_offer::parser::resupply_offer_body;
68use crate::resupply_received::parser::resupply_received_body;
69use crate::sees::parser::sees_body;
70use crate::service_request::parser::service_request_body;
71use crate::set_data_r::parser::set_data_r_body;
72use crate::set_record_r::parser::set_record_r_body;
73use crate::start_resume_r::parser::start_resume_r_body;
74use crate::stop_freeze_r::parser::stop_freeze_r_body;
75use crate::transfer_ownership::parser::transfer_ownership_body;
76use crate::underwater_acoustic::parser::underwater_acoustic_body;
77use crate::v7::parser::parse_pdu_status;
78use nom::bytes::complete::take;
79use nom::combinator::peek;
80use nom::error::ErrorKind::Eof;
81use nom::multi::{count, many1};
82use nom::number::complete::{be_f32, be_f64, be_i32, be_u16, be_u32, be_u64, be_u8};
83use nom::sequence::tuple;
84use nom::Err;
85use nom::IResult;
86
87pub(crate) fn parse_multiple_pdu(input: &[u8]) -> Result<Vec<Pdu>, DisError> {
88    match many1(pdu)(input) {
89        Ok((_, pdus)) => Ok(pdus),
90        Err(err) => Err(DisError::ParseError(err.to_string())), // TODO not very descriptive / error means we can not match any PDUs
91    }
92}
93
94#[allow(dead_code)]
95pub(crate) fn parse_pdu(input: &[u8]) -> Result<Pdu, DisError> {
96    match pdu(input) {
97        Ok((_, pdu)) => Ok(pdu),
98        Err(err) => Err(DisError::ParseError(err.to_string())), // TODO not very descriptive / error means we can not match any PDUs
99    }
100}
101
102#[allow(dead_code)]
103pub(crate) fn parse_multiple_header(input: &[u8]) -> Result<Vec<PduHeader>, DisError> {
104    match many1(pdu_header_skip_body)(input) {
105        Ok((_, headers)) => Ok(headers),
106        Err(parse_error) => {
107            if let Err::Error(ref error) = parse_error {
108                if error.code == Eof {
109                    return Err(DisError::InsufficientHeaderLength(input.len() as u16));
110                }
111            }
112            Err(DisError::ParseError(parse_error.to_string()))
113        }
114    }
115}
116
117/// Parse the input for a PDU header, and skip the rest of the pdu body in the input
118#[allow(dead_code)]
119pub(crate) fn parse_header(input: &[u8]) -> Result<PduHeader, DisError> {
120    match pdu_header(input) {
121        Ok((input, header)) => {
122            let skipped = skip_body(header.pdu_length)(input); // Discard the body
123            if let Err(Err::Error(error)) = skipped {
124                return if error.code == Eof {
125                    Err(DisError::InsufficientPduLength(
126                        header.pdu_length - PDU_HEADER_LEN_BYTES,
127                        input.len() as u16,
128                    ))
129                } else {
130                    Err(DisError::ParseError(
131                        "ParseError while parsing a pdu header and skipping body.".to_string(),
132                    ))
133                };
134            }
135            Ok(header)
136        }
137        Err(parse_error) => {
138            if let Err::Error(ref error) = parse_error {
139                if error.code == Eof {
140                    return Err(DisError::InsufficientHeaderLength(input.len() as u16));
141                }
142            }
143            Err(DisError::ParseError(parse_error.to_string()))
144        }
145    }
146}
147
148fn pdu(input: &[u8]) -> IResult<&[u8], Pdu> {
149    // parse the header
150    let (input, header) = pdu_header(input)?;
151
152    // if (header.pdu_length - PDU_HEADER_LEN_BYTES) as usize > input.len() {
153    //     // FIXME signal correct sort of error when the input is too small for the indicated PDU length
154    //     return nom::error::make_error(input, nom::error::ErrorKind::Eof);
155    // }
156
157    // parse the body based on the type
158    // and produce the final pdu combined with the header
159    let (input, body) = pdu_body(&header)(input)?;
160
161    Ok((input, Pdu { header, body }))
162}
163
164fn pdu_header(input: &[u8]) -> IResult<&[u8], PduHeader> {
165    let protocol_version = protocol_version;
166    let exercise_id = be_u8;
167    let pdu_type = pdu_type;
168    let protocol_family = protocol_family;
169    let time_stamp = be_u32;
170    let pdu_length = be_u16;
171
172    let (input, (protocol_version, exercise_id, pdu_type, protocol_family, time_stamp, pdu_length)) =
173        tuple((
174            protocol_version,
175            exercise_id,
176            pdu_type,
177            protocol_family,
178            time_stamp,
179            pdu_length,
180        ))(input)?;
181    let (input, pdu_status, padding) = match u8::from(protocol_version) {
182        legacy_version if (1..=5).contains(&legacy_version) => {
183            let (input, padding) = be_u16(input)?;
184            (input, None, padding)
185        }
186        6 => {
187            let (input, padding) = be_u16(input)?;
188            (input, None, padding)
189        }
190        7 => {
191            let (input, (status, padding)) = parse_pdu_status(pdu_type)(input)?;
192            (input, Some(status), padding)
193        }
194        _future_version => {
195            let (input, (status, padding)) = parse_pdu_status(pdu_type)(input)?;
196            (input, Some(status), padding)
197        }
198    };
199
200    Ok((
201        input,
202        PduHeader {
203            protocol_version,
204            exercise_id,
205            pdu_type,
206            protocol_family,
207            time_stamp,
208            pdu_length,
209            pdu_status,
210            padding,
211        },
212    ))
213}
214
215#[allow(dead_code)]
216fn pdu_header_skip_body(input: &[u8]) -> IResult<&[u8], PduHeader> {
217    let (input, header) = pdu_header(input)?;
218    let (input, _) = skip_body(header.pdu_length)(input)?;
219    Ok((input, header))
220}
221
222fn pdu_body(header: &PduHeader) -> impl Fn(&[u8]) -> IResult<&[u8], PduBody> + '_ {
223    move |input: &[u8]| {
224        // parse the body of the PDU based on the type
225        // NOTE only processes supported PduTypes; process others as 'Other'
226        let (input, body) = match header.pdu_type {
227            PduType::Other => other_body(header)(input)?,
228            PduType::EntityState => entity_state_body(header)(input)?,
229            PduType::Fire => fire_body(header)(input)?,
230            PduType::Detonation => detonation_body(header)(input)?,
231            PduType::Collision => collision_body(input)?,
232            PduType::ServiceRequest => service_request_body(input)?,
233            PduType::ResupplyOffer => resupply_offer_body(input)?,
234            PduType::ResupplyReceived => resupply_received_body(input)?,
235            PduType::ResupplyCancel => resupply_cancel_body(input)?,
236            PduType::RepairComplete => repair_complete_body(input)?,
237            PduType::RepairResponse => repair_response_body(input)?,
238            PduType::CreateEntity => create_entity_body(input)?,
239            PduType::RemoveEntity => remove_entity_body(input)?,
240            PduType::StartResume => start_resume_body(input)?,
241            PduType::StopFreeze => stop_freeze_body(input)?,
242            PduType::Acknowledge => acknowledge_body(input)?,
243            PduType::ActionRequest => action_request_body(input)?,
244            PduType::ActionResponse => action_response_body(input)?,
245            PduType::DataQuery => data_query_body(input)?,
246            PduType::SetData => set_data_body(input)?,
247            PduType::Data => data_body(input)?,
248            PduType::EventReport => event_report_body(input)?,
249            PduType::Comment => comment_body(input)?,
250            PduType::ElectromagneticEmission => emission_body(header)(input)?,
251            PduType::Designator => designator_body(input)?,
252            PduType::Transmitter => transmitter_body(header)(input)?,
253            PduType::Signal => signal_body(input)?,
254            PduType::Receiver => receiver_body(input)?,
255            PduType::IFF => iff_body(input)?,
256            PduType::UnderwaterAcoustic => underwater_acoustic_body(input)?,
257            PduType::SupplementalEmissionEntityState => sees_body(input)?,
258            // PduType::IntercomSignal => {}
259            // PduType::IntercomControl => {}
260            PduType::AggregateState => aggregate_state_body(input)?,
261            PduType::IsGroupOf => is_group_of_body(input)?,
262            PduType::TransferOwnership => transfer_ownership_body(input)?,
263            PduType::IsPartOf => is_part_of_body(input)?,
264            // PduType::MinefieldState => {}
265            // PduType::MinefieldQuery => {}
266            // PduType::MinefieldData => {}
267            // PduType::MinefieldResponseNACK => {}
268            // PduType::EnvironmentalProcess => {}
269            // PduType::GriddedData => {}
270            // PduType::PointObjectState => {}
271            // PduType::LinearObjectState => {}
272            // PduType::ArealObjectState => {}
273            // PduType::TSPI => {}
274            // PduType::Appearance => {}
275            // PduType::ArticulatedParts => {}
276            // PduType::LEFire => {}
277            // PduType::LEDetonation => {}
278            PduType::CreateEntityR => create_entity_r_body(input)?,
279            PduType::RemoveEntityR => remove_entity_r_body(input)?,
280            PduType::StartResumeR => start_resume_r_body(input)?,
281            PduType::StopFreezeR => stop_freeze_r_body(input)?,
282            PduType::AcknowledgeR => acknowledge_r_body(input)?,
283            PduType::ActionRequestR => action_request_r_body(input)?,
284            PduType::ActionResponseR => action_response_r_body(input)?,
285            PduType::DataQueryR => data_query_r_body(input)?,
286            PduType::SetDataR => set_data_r_body(input)?,
287            PduType::DataR => data_r_body(input)?,
288            PduType::EventReportR => event_report_r_body(input)?,
289            PduType::CommentR => comment_r_body(input)?,
290            PduType::RecordR => record_r_body(input)?,
291            PduType::SetRecordR => set_record_r_body(input)?,
292            PduType::RecordQueryR => record_query_r_body(input)?,
293            PduType::CollisionElastic => collision_elastic_body(input)?,
294            PduType::EntityStateUpdate => entity_state_update_body(input)?,
295            // PduType::DirectedEnergyFire => {}
296            // PduType::EntityDamageStatus => {}
297            // PduType::InformationOperationsAction => {}
298            // PduType::InformationOperationsReport => {}
299            PduType::Attribute => attribute_body(input)?,
300            PduType::Unspecified(_type_number) => other_body(header)(input)?, // TODO Log unsupported type number?
301            _ => other_body(header)(input)?,
302        };
303        Ok((input, body))
304    }
305}
306
307#[allow(dead_code)]
308pub(crate) fn parse_peek_protocol_version(input: &[u8]) -> Result<ProtocolVersion, DisError> {
309    let parse_result = peek_protocol_version(input);
310    match parse_result {
311        Ok((_, protocol_version)) => Ok(ProtocolVersion::from(protocol_version)),
312        Err(err) => Err(DisError::ParseError(err.to_string())),
313    }
314}
315
316/// Function tries to peek the protocol version field of the DIS header
317/// and return the raw value when successful.
318#[allow(dead_code)]
319fn peek_protocol_version(input: &[u8]) -> IResult<&[u8], u8> {
320    let (input, protocol_version) = peek(be_u8)(input)?;
321    Ok((input, protocol_version))
322}
323
324pub(crate) fn protocol_version(input: &[u8]) -> IResult<&[u8], ProtocolVersion> {
325    let (input, protocol_version) = be_u8(input)?;
326    let protocol_version = ProtocolVersion::from(protocol_version);
327    Ok((input, protocol_version))
328}
329
330pub(crate) fn pdu_type(input: &[u8]) -> IResult<&[u8], PduType> {
331    let (input, pdu_type) = be_u8(input)?;
332    let pdu_type = PduType::from(pdu_type);
333    Ok((input, pdu_type))
334}
335
336pub(crate) fn protocol_family(input: &[u8]) -> IResult<&[u8], ProtocolFamily> {
337    let (input, protocol_family) = be_u8(input)?;
338    let protocol_family = ProtocolFamily::from(protocol_family);
339    Ok((input, protocol_family))
340}
341
342/// Skip the bytes of a PDU's body, by calculating the total length minus the length of a header.
343/// The function will skip zero bytes when the total length provided is less than the length of a header (12 bytes).
344#[allow(dead_code)]
345pub(crate) fn skip_body(total_bytes: u16) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> {
346    // if total_bytes <= PDU_HEADER_LEN_BYTES {
347    //     return Err(nom::error::Error {
348    //         input: (),
349    //         code: ErrorKind::Tag,
350    //     } )
351    // }
352    let bytes_to_skip = total_bytes.saturating_sub(PDU_HEADER_LEN_BYTES);
353    move |input| take(bytes_to_skip)(input)
354}
355
356pub(crate) fn simulation_address(input: &[u8]) -> IResult<&[u8], SimulationAddress> {
357    let (input, site_id) = be_u16(input)?;
358    let (input, application_id) = be_u16(input)?;
359    Ok((input, SimulationAddress::new(site_id, application_id)))
360}
361
362pub(crate) fn entity_id(input: &[u8]) -> IResult<&[u8], EntityId> {
363    let (input, simulation_address) = simulation_address(input)?;
364    let (input, entity_id) = be_u16(input)?;
365    Ok((
366        input,
367        EntityId {
368            simulation_address,
369            entity_id,
370        },
371    ))
372}
373
374pub(crate) fn entity_type(input: &[u8]) -> IResult<&[u8], EntityType> {
375    let (input, kind) = kind(input)?;
376    let (input, domain) = domain(input)?;
377    let (input, country) = country(input)?;
378    let (input, category) = be_u8(input)?;
379    let (input, subcategory) = be_u8(input)?;
380    let (input, specific) = be_u8(input)?;
381    let (input, extra) = be_u8(input)?;
382    Ok((
383        input,
384        EntityType {
385            kind,
386            domain,
387            country,
388            category,
389            subcategory,
390            specific,
391            extra,
392        },
393    ))
394}
395
396fn kind(input: &[u8]) -> IResult<&[u8], EntityKind> {
397    let (input, kind) = be_u8(input)?;
398    let kind = EntityKind::from(kind);
399    Ok((input, kind))
400}
401
402fn domain(input: &[u8]) -> IResult<&[u8], PlatformDomain> {
403    let (input, domain) = be_u8(input)?;
404    let domain = PlatformDomain::from(domain);
405    Ok((input, domain))
406}
407
408fn country(input: &[u8]) -> IResult<&[u8], Country> {
409    let (input, country) = be_u16(input)?;
410    let country = Country::from(country);
411    Ok((input, country))
412}
413
414pub(crate) fn vec3_f32(input: &[u8]) -> IResult<&[u8], VectorF32> {
415    let (input, elements) = count(be_f32, 3)(input)?;
416    #[allow(clippy::get_first)]
417    Ok((
418        input,
419        VectorF32 {
420            first_vector_component: *elements
421                .get(0)
422                .expect("Value supposed to be parsed successfully"),
423            second_vector_component: *elements
424                .get(1)
425                .expect("Value supposed to be parsed successfully"),
426            third_vector_component: *elements
427                .get(2)
428                .expect("Value supposed to be parsed successfully"),
429        },
430    ))
431}
432
433pub(crate) fn location(input: &[u8]) -> IResult<&[u8], Location> {
434    let (input, locations) = count(be_f64, 3)(input)?;
435    #[allow(clippy::get_first)]
436    Ok((
437        input,
438        Location {
439            x_coordinate: *locations
440                .get(0)
441                .expect("Value supposed to be parsed successfully"),
442            y_coordinate: *locations
443                .get(1)
444                .expect("Value supposed to be parsed successfully"),
445            z_coordinate: *locations
446                .get(2)
447                .expect("Value supposed to be parsed successfully"),
448        },
449    ))
450}
451
452pub(crate) fn orientation(input: &[u8]) -> IResult<&[u8], Orientation> {
453    let (input, orientations) = count(be_f32, 3)(input)?;
454    #[allow(clippy::get_first)]
455    Ok((
456        input,
457        Orientation {
458            psi: *orientations
459                .get(0)
460                .expect("Value supposed to be parsed successfully"),
461            theta: *orientations
462                .get(1)
463                .expect("Value supposed to be parsed successfully"),
464            phi: *orientations
465                .get(2)
466                .expect("Value supposed to be parsed successfully"),
467        },
468    ))
469}
470
471pub(crate) fn event_id(input: &[u8]) -> IResult<&[u8], EventId> {
472    let (input, site_id) = be_u16(input)?;
473    let (input, application_id) = be_u16(input)?;
474    let (input, event_id) = be_u16(input)?;
475    Ok((
476        input,
477        EventId {
478            simulation_address: SimulationAddress {
479                site_id,
480                application_id,
481            },
482            event_id,
483        },
484    ))
485}
486
487pub(crate) fn descriptor_record_fti(
488    fire_type_indicator: FireTypeIndicator,
489) -> impl Fn(&[u8]) -> IResult<&[u8], DescriptorRecord> {
490    move |input: &[u8]| {
491        let (input, entity_type) = entity_type(input)?;
492
493        match fire_type_indicator {
494            FireTypeIndicator::Munition => {
495                let (input, munition) = munition_descriptor(input)?;
496
497                Ok((
498                    input,
499                    DescriptorRecord::Munition {
500                        entity_type,
501                        munition,
502                    },
503                ))
504            }
505            FireTypeIndicator::Expendable => {
506                let (input, _pad_out) = be_u64(input)?;
507
508                Ok((input, DescriptorRecord::Expendable { entity_type }))
509            }
510            FireTypeIndicator::Unspecified(_) => {
511                // TODO should be an error; parse as Expendable, which has no data, for now
512                let (input, _pad_out) = be_u64(input)?;
513
514                Ok((input, DescriptorRecord::Expendable { entity_type }))
515            }
516        }
517    }
518}
519
520pub(crate) fn descriptor_record_dti(
521    detonation_type_indicator: DetonationTypeIndicator,
522) -> impl Fn(&[u8]) -> IResult<&[u8], DescriptorRecord> {
523    move |input: &[u8]| {
524        let (input, entity_type) = entity_type(input)?;
525        match detonation_type_indicator {
526            DetonationTypeIndicator::Munition => {
527                let (input, munition) = munition_descriptor(input)?;
528
529                Ok((
530                    input,
531                    DescriptorRecord::Munition {
532                        entity_type,
533                        munition,
534                    },
535                ))
536            }
537            DetonationTypeIndicator::Expendable => {
538                let (input, _pad_out) = be_u64(input)?;
539                Ok((input, DescriptorRecord::Expendable { entity_type }))
540            }
541            DetonationTypeIndicator::NonmunitionExplosion => {
542                let (input, explosive_material) = be_u16(input)?;
543                let explosive_material = ExplosiveMaterialCategories::from(explosive_material);
544                let (input, explosive_force) = be_f32(input)?;
545
546                Ok((
547                    input,
548                    DescriptorRecord::Explosion {
549                        entity_type,
550                        explosive_material,
551                        explosive_force,
552                    },
553                ))
554            }
555            DetonationTypeIndicator::Unspecified(_) => {
556                // TODO should be an error; parse as Expendable, which has no data, for now
557                let (input, _pad_out) = be_u64(input)?;
558                Ok((input, DescriptorRecord::Expendable { entity_type }))
559            }
560        }
561    }
562}
563
564pub(crate) fn munition_descriptor(input: &[u8]) -> IResult<&[u8], MunitionDescriptor> {
565    let (input, warhead) = warhead(input)?;
566    let (input, fuse) = fuse(input)?;
567    let (input, quantity) = be_u16(input)?;
568    let (input, rate) = be_u16(input)?;
569
570    Ok((
571        input,
572        MunitionDescriptor {
573            warhead,
574            fuse,
575            quantity,
576            rate,
577        },
578    ))
579}
580
581fn warhead(input: &[u8]) -> IResult<&[u8], MunitionDescriptorWarhead> {
582    let (input, warhead) = be_u16(input)?;
583    let warhead = MunitionDescriptorWarhead::from(warhead);
584    Ok((input, warhead))
585}
586
587fn fuse(input: &[u8]) -> IResult<&[u8], MunitionDescriptorFuse> {
588    let (input, fuse) = be_u16(input)?;
589    let fuse = MunitionDescriptorFuse::from(fuse);
590    Ok((input, fuse))
591}
592
593pub(crate) fn clock_time(input: &[u8]) -> IResult<&[u8], ClockTime> {
594    let (input, hour) = be_i32(input)?;
595    let (input, time_past_hour) = be_u32(input)?;
596    let time = ClockTime::new(hour, time_past_hour);
597    Ok((input, time))
598}
599
600pub(crate) fn datum_specification(input: &[u8]) -> IResult<&[u8], DatumSpecification> {
601    let (input, num_fixed_datums) = be_u32(input)?;
602    let (input, num_variable_datums) = be_u32(input)?;
603
604    let (input, fixed_datums) = count(fixed_datum, num_fixed_datums as usize)(input)?;
605    let (input, variable_datums) = count(variable_datum, num_variable_datums as usize)(input)?;
606
607    let datums = DatumSpecification::new(fixed_datums, variable_datums);
608
609    Ok((input, datums))
610}
611
612pub(crate) fn fixed_datum(input: &[u8]) -> IResult<&[u8], FixedDatum> {
613    let (input, datum_id) = be_u32(input)?;
614    let (input, datum_value) = be_u32(input)?;
615
616    let datum_id = VariableRecordType::from(datum_id);
617    let datum = FixedDatum::new(datum_id, datum_value);
618
619    Ok((input, datum))
620}
621
622pub(crate) fn variable_datum(input: &[u8]) -> IResult<&[u8], VariableDatum> {
623    let (input, datum_id) = be_u32(input)?;
624    let datum_id = VariableRecordType::from(datum_id);
625    let (input, datum_length_bits) = be_u32(input)?;
626
627    // NOTE: The standard defines the data length and padding in bits.
628    // However, we assume that one only puts in values that consists of whole bytes.
629    // (As why would one put 11 bits in a datum, which then ends up in a Vec<u8>)
630    let datum_length_bytes = datum_length_bits as usize / ONE_BYTE_IN_BITS;
631    let padded_record = length_padded_to_num(datum_length_bytes, EIGHT_OCTETS);
632
633    let (input, datum_value) = take(padded_record.data_length)(input)?;
634    let (input, _datum_padding) = take(padded_record.padding_length)(input)?;
635
636    let variable_datum = VariableDatum::new(datum_id, datum_value.to_vec());
637
638    Ok((input, variable_datum))
639}
640
641pub(crate) fn variable_parameter(input: &[u8]) -> IResult<&[u8], VariableParameter> {
642    let (input, parameter_type_designator) = be_u8(input)?;
643    let parameter_type = VariableParameterRecordType::from(parameter_type_designator);
644    let (input, variable_parameter) = match parameter_type {
645        VariableParameterRecordType::ArticulatedPart => articulated_part(input)?,
646        VariableParameterRecordType::AttachedPart => attached_part(input)?,
647        VariableParameterRecordType::Separation => separation(input)?,
648        VariableParameterRecordType::EntityType => entity_type_variable_parameter(input)?,
649        VariableParameterRecordType::EntityAssociation => entity_association(input)?,
650        VariableParameterRecordType::Unspecified(_) => {
651            let (input, bytes) = take(15usize)(input)?;
652            (
653                input,
654                VariableParameter::Unspecified(
655                    parameter_type_designator,
656                    <[u8; 15]>::try_from(bytes).unwrap(),
657                ),
658            )
659        } // TODO sensible error
660    };
661
662    Ok((input, variable_parameter))
663}
664
665/// I.2.2 Articulated parts
666fn articulated_part(input: &[u8]) -> IResult<&[u8], VariableParameter> {
667    let (input, change_indicator) = be_u8(input)?;
668    let change_indicator = ChangeIndicator::from(change_indicator);
669    let (input, attachment_id) = be_u16(input)?;
670    let (input, parameter_type) = be_u32(input)?; // Parameter Type = Type Class + Type Metric
671    let type_metric: u32 = parameter_type & FIVE_LEAST_SIGNIFICANT_BITS; // 5 least significant bits are the Type Metric
672    let type_class: u32 = parameter_type - type_metric; // Rest of the bits (Param Type minus Type Metric) are the Type Class
673    let (input, value) = be_f32(input)?;
674    let (input, _pad_out) = be_u32(input)?;
675
676    Ok((
677        input,
678        VariableParameter::Articulated(ArticulatedPart {
679            change_indicator,
680            attachment_id,
681            type_metric: ArticulatedPartsTypeMetric::from(type_metric),
682            type_class: ArticulatedPartsTypeClass::from(type_class),
683            parameter_value: value,
684        }),
685    ))
686}
687
688fn attached_part(input: &[u8]) -> IResult<&[u8], VariableParameter> {
689    let (input, detached_indicator) = be_u8(input)?;
690    let detached_indicator = AttachedPartDetachedIndicator::from(detached_indicator);
691    let (input, attachment_id) = be_u16(input)?;
692    let (input, attached_part) = be_u32(input)?;
693    let (input, entity_type) = entity_type(input)?;
694
695    Ok((
696        input,
697        VariableParameter::Attached(AttachedPart {
698            detached_indicator,
699            attachment_id,
700            parameter_type: AttachedParts::from(attached_part),
701            attached_part_type: entity_type,
702        }),
703    ))
704}
705
706fn entity_association(input: &[u8]) -> IResult<&[u8], VariableParameter> {
707    let (input, change_indicator) = be_u8(input)?;
708    let (input, association_status) = be_u8(input)?;
709    let (input, association_type) = be_u8(input)?;
710    let (input, entity_id) = entity_id(input)?;
711    let (input, own_station_location) = be_u16(input)?;
712    let (input, physical_connection_type) = be_u8(input)?;
713    let (input, group_member_type) = be_u8(input)?;
714    let (input, group_number) = be_u16(input)?;
715
716    Ok((
717        input,
718        VariableParameter::EntityAssociation(EntityAssociationParameter {
719            change_indicator: ChangeIndicator::from(change_indicator),
720            association_status: EntityAssociationAssociationStatus::from(association_status),
721            association_type: EntityAssociationPhysicalAssociationType::from(association_type),
722            entity_id,
723            own_station_location: StationName::from(own_station_location),
724            physical_connection_type: EntityAssociationPhysicalConnectionType::from(
725                physical_connection_type,
726            ),
727            group_member_type: EntityAssociationGroupMemberType::from(group_member_type),
728            group_number,
729        }),
730    ))
731}
732
733fn entity_type_variable_parameter(input: &[u8]) -> IResult<&[u8], VariableParameter> {
734    let (input, change_indicator) = be_u8(input)?;
735    let (input, entity_type) = entity_type(input)?;
736    let (input, _pad_out_16) = be_u16(input)?;
737    let (input, _pad_out_32) = be_u32(input)?;
738
739    Ok((
740        input,
741        VariableParameter::EntityType(EntityTypeParameter {
742            change_indicator: ChangeIndicator::from(change_indicator),
743            entity_type,
744        }),
745    ))
746}
747
748fn separation(input: &[u8]) -> IResult<&[u8], VariableParameter> {
749    let (input, reason) = be_u8(input)?;
750    let (input, pre_entity_indicator) = be_u8(input)?;
751    let (input, parent_entity_id) = entity_id(input)?;
752    let (input, _pad_16) = be_u16(input)?;
753    let (input, station_name) = be_u16(input)?;
754    let (input, station_number) = be_u16(input)?;
755
756    Ok((
757        input,
758        VariableParameter::Separation(SeparationParameter {
759            reason: SeparationReasonForSeparation::from(reason),
760            pre_entity_indicator: SeparationPreEntityIndicator::from(pre_entity_indicator),
761            parent_entity_id,
762            station_name: StationName::from(station_name),
763            station_number,
764        }),
765    ))
766}
767
768pub(crate) fn beam_data(input: &[u8]) -> IResult<&[u8], BeamData> {
769    let (input, azimuth_center) = be_f32(input)?;
770    let (input, azimuth_sweep) = be_f32(input)?;
771    let (input, elevation_center) = be_f32(input)?;
772    let (input, elevation_sweep) = be_f32(input)?;
773    let (input, sweep_sync) = be_f32(input)?;
774
775    let data = BeamData::new()
776        .with_azimuth_center(azimuth_center)
777        .with_azimuth_sweep(azimuth_sweep)
778        .with_elevation_center(elevation_center)
779        .with_elevation_sweep(elevation_sweep)
780        .with_sweep_sync(sweep_sync);
781
782    Ok((input, data))
783}
784
785pub(crate) fn supply_quantity(input: &[u8]) -> IResult<&[u8], SupplyQuantity> {
786    let (input, supply_type) = entity_type(input)?;
787    let (input, quantity) = be_f32(input)?;
788
789    Ok((
790        input,
791        SupplyQuantity::default()
792            .with_supply_type(supply_type)
793            .with_quantity(quantity),
794    ))
795}
796
797/// Parses the `RecordSpecification` record (6.2.73)
798pub(crate) fn record_specification(input: &[u8]) -> IResult<&[u8], RecordSpecification> {
799    let (input, number_of_records) = be_u32(input)?;
800    let (input, record_sets) = count(record_set, number_of_records as usize)(input)?;
801
802    Ok((
803        input,
804        RecordSpecification::default().with_record_sets(record_sets),
805    ))
806}
807
808/// Parses a Record Set as part of a `RecordSpecification` record (6.2.73).
809///
810/// Parsing will always consider record values to be byte-aligned.
811/// Record length is defined in bits, but this function always rounds up to the next full byte.
812/// This is compensated for in the padding.
813pub(crate) fn record_set(input: &[u8]) -> IResult<&[u8], RecordSet> {
814    let (input, record_id) = be_u32(input)?;
815    let record_id = VariableRecordType::from(record_id);
816    let (input, serial_number) = be_u32(input)?;
817    let (input, _padding) = be_u32(input)?;
818    let (input, record_length_bits) = be_u16(input)?;
819    let record_length_bytes = ceil_bits_to_bytes(record_length_bits);
820    let (input, record_count) = be_u16(input)?;
821    let (input, record_values): (&[u8], Vec<&[u8]>) =
822        count(take(record_length_bytes), record_count as usize)(input)?;
823    let record_values = record_values.iter().map(|values| values.to_vec()).collect();
824    let padded_record_length =
825        length_padded_to_num((record_length_bytes * record_count) as usize, EIGHT_OCTETS);
826    let (input, _padding) = take(padded_record_length.padding_length)(input)?;
827
828    Ok((
829        input,
830        RecordSet::default()
831            .with_record_id(record_id)
832            .with_record_serial_number(serial_number)
833            .with_records(record_values),
834    ))
835}
836
837/// Takes a reference to a buffer and converts the contents into a String,
838/// sanitizing the input on leading/ending whitespace, and
839/// keeping only alphanumeric characters.
840pub(crate) fn sanitize_marking(buf: &[u8]) -> String {
841    let mut marking_string = String::from_utf8_lossy(buf).into_owned();
842    marking_string.truncate(
843        marking_string
844            .trim_end()
845            .trim_end_matches(|c: char| !c.is_alphanumeric())
846            .len(),
847    );
848
849    marking_string
850}
851
852/// Round upward a given number of bits to the next amount of full bytes
853///
854/// E.g., 7 bits become 1 byte (8 bits), 12 bits become 2 bytes (16 bits)
855fn ceil_bits_to_bytes(bits: u16) -> u16 {
856    bits.div_ceil(ONE_BYTE_IN_BITS as u16)
857}
858
859#[cfg(test)]
860mod tests {
861    use crate::common::errors::DisError;
862    use crate::common::parser::{parse_multiple_header, skip_body};
863    use crate::constants::PDU_HEADER_LEN_BYTES;
864    use crate::enumerations::{PduType, ProtocolFamily, ProtocolVersion};
865
866    #[test]
867    fn parse_header() {
868        let bytes: [u8; 12] = [
869            0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
870        ];
871
872        let header = crate::common::parser::parse_header(&bytes);
873        assert!(header.is_ok());
874        let header = header.unwrap();
875        assert_eq!(header.protocol_version, ProtocolVersion::IEEE1278_1A1998);
876        assert_eq!(header.exercise_id, 1);
877        assert_eq!(header.pdu_type, PduType::EntityState);
878        assert_eq!(
879            header.protocol_family,
880            ProtocolFamily::EntityInformationInteraction
881        );
882        assert_eq!(header.time_stamp, 1_323_973_472);
883        assert_eq!(header.pdu_length, { PDU_HEADER_LEN_BYTES }); // only the header, 0-bytes pdu body
884    }
885
886    #[test]
887    fn parse_header_too_short() {
888        let bytes: [u8; 10] = [0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x60];
889
890        let header = crate::common::parser::parse_header(&bytes);
891        assert!(header.is_err());
892        let error = header.expect_err("Should be Err");
893        assert_eq!(error, DisError::InsufficientHeaderLength(10));
894    }
895
896    #[test]
897    fn parse_header_unspecified_version() {
898        let bytes: [u8; 12] = [
899            0x1F, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
900        ];
901
902        let header = crate::common::parser::parse_header(&bytes);
903        assert!(header.is_ok());
904        let header = header.unwrap();
905        assert_eq!(header.protocol_version, ProtocolVersion::Unspecified(31));
906        assert_eq!(header.exercise_id, 1);
907        assert_eq!(header.pdu_type, PduType::EntityState);
908        assert_eq!(
909            header.protocol_family,
910            ProtocolFamily::EntityInformationInteraction
911        );
912        assert_eq!(header.time_stamp, 1_323_973_472);
913        assert_eq!(header.pdu_length, { PDU_HEADER_LEN_BYTES }); // only the header, 0-bytes pdu body
914    }
915
916    #[test]
917    fn parse_header_body_too_short() {
918        // PDU with header that states that the total length is 208 bytes, but only contains a 2 bytes body;
919        let bytes: [u8; 14] = [
920            0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0xd0, 0x00, 0x00, 0x01, 0xf4,
921        ];
922
923        let header = crate::common::parser::parse_header(&bytes);
924        assert!(header.is_err());
925        let error = header.expect_err("Should be Err");
926        assert_eq!(
927            error,
928            DisError::InsufficientPduLength(208 - PDU_HEADER_LEN_BYTES, 2)
929        );
930    }
931
932    #[test]
933    fn parse_multiple_headers() {
934        let bytes: [u8; 24] = [
935            0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00, 0x06, 0x01,
936            0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
937        ];
938
939        let headers = parse_multiple_header(&bytes);
940        assert!(headers.is_ok());
941        let headers = headers.unwrap();
942        assert_eq!(headers.len(), 2);
943    }
944
945    #[test]
946    fn parse_multiple_headers_1st_too_short() {
947        let bytes: [u8; 23] = [
948            0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x06, 0x01, 0x01,
949            0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
950        ];
951        // two pdus, headers with 0-byte body's; first header is one-byte short
952
953        let headers = parse_multiple_header(&bytes);
954        assert!(headers.is_ok());
955        let headers = headers.unwrap();
956        assert_eq!(headers.len(), 1);
957        let header = headers.first().unwrap();
958        assert_ne!(header.padding, 0); // padding is not zero, because first byte of the next headers is there
959    }
960
961    #[test]
962    fn parse_multiple_headers_too_short() {
963        let bytes: [u8; 11] = [
964            0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x60, 0x00,
965        ];
966        // buffer is too short for one pdu, let alone multiple.
967
968        let headers = parse_multiple_header(&bytes);
969        assert!(headers.is_err());
970        let error = headers.expect_err("Should be Err");
971        assert_eq!(error, DisError::InsufficientHeaderLength(11));
972    }
973
974    #[test]
975    fn skip_body_total_length_cannot_contain_a_header() {
976        let bytes: [u8; 2] = [0x00, 0x00];
977
978        let (input, skipped) = skip_body(2)(&bytes).unwrap();
979        assert_eq!(input, [0x00, 0x00]);
980        assert_eq!(skipped, []);
981    }
982}