Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ impl FitParser {
self.read_u8().unwrap_or(0),
self.read_u8().unwrap_or(0),
];
if signature != [b'.', b'F', b'I', b'T'] {
if signature != *b".FIT" {
return coordinates;
}

Expand Down Expand Up @@ -890,7 +890,7 @@ impl FitParser {
// Latitude field
if field.size == 4 {
if let Some(lat_raw) = self.read_i32_le() {
if lat_raw != 0x7FFFFFFF && lat_raw != 0 {
if lat_raw != 0x7FFFFFFF {
let lat_degrees = lat_raw as f64 * (180.0 / 2147483648.0);
if lat_degrees.abs() <= 90.0 {
lat = Some(lat_degrees);
Expand All @@ -905,7 +905,7 @@ impl FitParser {
// Longitude field
if field.size == 4 {
if let Some(lon_raw) = self.read_i32_le() {
if lon_raw != 0x7FFFFFFF && lon_raw != 0 {
if lon_raw != 0x7FFFFFFF {
let lon_degrees = lon_raw as f64 * (180.0 / 2147483648.0);
if lon_degrees.abs() <= 180.0 {
lon = Some(lon_degrees);
Expand All @@ -924,7 +924,11 @@ impl FitParser {
}

if let (Some(lat_val), Some(lon_val)) = (lat, lon) {
Some([round(lat_val), round(lon_val)])
if is_valid_coordinate(lat_val, lon_val) {
Some([round(lat_val), round(lon_val)])
} else {
None
}
} else {
None
}
Expand Down
68 changes: 68 additions & 0 deletions core/tests/fit_parser_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,74 @@ mod fit_parser_tests {
assert!(result.is_none());
}

#[test]
fn test_parse_record_message_equator() {
let definition = create_test_message_definition(20);
for longitude in [-45.0, 45.0] {
let mut data = Vec::new();
data.extend_from_slice(&0i32.to_le_bytes());
data.extend_from_slice(&((longitude * 2147483648.0 / 180.0) as i32).to_le_bytes());
data.extend_from_slice(&1234u16.to_le_bytes());

let mut parser = create_test_parser(data);
assert_eq!(
parser.parse_record_message(&definition),
Some([0.0, longitude])
);
assert_eq!(parser.pos, parser.data.len());
}
}

#[test]
fn test_parse_record_message_prime_meridian() {
let definition = create_test_message_definition(20);
for latitude in [-45.0, 45.0] {
let mut data = Vec::new();
data.extend_from_slice(&((latitude * 2147483648.0 / 180.0) as i32).to_le_bytes());
data.extend_from_slice(&0i32.to_le_bytes());
data.extend_from_slice(&1234u16.to_le_bytes());

let mut parser = create_test_parser(data);
assert_eq!(
parser.parse_record_message(&definition),
Some([latitude, 0.0])
);
assert_eq!(parser.pos, parser.data.len());
}
}

#[test]
fn test_parse_gps_coordinates_zero_axes() {
// A local record definition with signed latitude and longitude fields.
let mut records = vec![0x40, 0, 0, 20, 0, 2, 0, 4, 0x85, 1, 4, 0x85];
let quarter_circle = 1i32 << 29; // 45 degrees in semicircles
for (lat, lon) in [
(0, quarter_circle),
(0, -quarter_circle),
(quarter_circle, 0),
(-quarter_circle, 0),
(i32::MAX, quarter_circle),
(quarter_circle, i32::MAX),
(0, 0),
] {
records.push(0); // Local record message header
records.extend_from_slice(&lat.to_le_bytes());
records.extend_from_slice(&lon.to_le_bytes());
}

let mut data = vec![12, 0x10, 0, 0];
data.extend_from_slice(&(records.len() as u32).to_le_bytes());
data.extend_from_slice(b".FIT");
data.extend_from_slice(&records);
data.extend_from_slice(&[0, 0]); // CRC is not checked by this parser

let mut parser = create_test_parser(data);
assert_eq!(
parser.parse_gps_coordinates(),
vec![[0.0, 45.0], [0.0, -45.0], [45.0, 0.0], [-45.0, 0.0]]
);
}

#[test]
fn test_parse_record_message_out_of_range_coordinates() {
let definition = create_test_message_definition(20);
Expand Down