use crate::error::{ErrorKind, Result};
use crate::profile::MesgNum;
use crate::{DeveloperFieldDescription, FitDataRecord};
use nom::number::complete::le_u16;
use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::io::Read;
use std::sync::Arc;
mod crc;
use crc::{caculate_crc, update_crc};
mod decode;
use decode::Decoder;
mod parser;
pub use parser::{FitDataMessage, FitDefinitionMessage, FitFileHeader};
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum DecodeOption {
DropUnknownFields,
DropUnknownMessages,
KeepCompositeFields,
ReturnNumericEnumValues,
SkipHeaderCrcValidation,
SkipDataCrcValidation,
UseGenericSubFieldName,
}
#[derive(Clone, Debug)]
pub enum FitObject {
Crc(u16),
Header(FitFileHeader),
DataMessage(FitDataMessage),
DefinitionMessage(Arc<FitDefinitionMessage>),
}
struct Deserializer {
options: HashSet<DecodeOption>,
definitions: HashMap<u8, Arc<FitDefinitionMessage>>,
position: usize,
end_of_messages: usize,
crc: u16,
}
impl Deserializer {
fn new() -> Self {
Deserializer {
options: HashSet::new(),
definitions: HashMap::new(),
position: 0,
end_of_messages: 0,
crc: 0,
}
}
fn options(&self) -> &HashSet<DecodeOption> {
&self.options
}
fn options_mut(&mut self) -> &mut HashSet<DecodeOption> {
&mut self.options
}
fn reset(&mut self) {
self.crc = 0;
self.definitions = HashMap::new();
}
fn deserialize_next<'de>(
&mut self,
input: &'de [u8],
developer_field_descriptions: &HashMap<(u8, u8), DeveloperFieldDescription>,
) -> Result<(&'de [u8], FitObject)> {
if self.position > 0 && self.position == self.end_of_messages {
return self.deserialize_crc(input);
}
if self.position == 0 || (self.position > self.end_of_messages && !input.is_empty()) {
return self.deserialize_header(input);
}
self.deserialize_message(input, developer_field_descriptions)
}
fn deserialize_header<'de>(&mut self, input: &'de [u8]) -> Result<(&'de [u8], FitObject)> {
let (remaining, header) =
parser::fit_file_header(input).map_err(|e| self.to_parse_err(e))?;
self.end_of_messages =
self.position + header.header_size() as usize + header.data_size() as usize;
self.position += header.header_size() as usize;
self.crc = 0;
let crc_value = header.crc().unwrap_or(0);
if crc_value > 0 {
let checksum = caculate_crc(&input[0..(header.header_size() - 2) as usize]);
if !self
.options
.contains(&DecodeOption::SkipHeaderCrcValidation)
&& checksum != crc_value
{
return Err(Box::new(ErrorKind::InvalidCrc((
Vec::from(remaining),
FitObject::Header(header),
crc_value,
checksum,
))));
}
} else {
self.crc = update_crc(0, &input[0..(header.header_size() as usize)]);
}
Ok((remaining, FitObject::Header(header)))
}
fn deserialize_crc<'de>(&mut self, input: &'de [u8]) -> Result<(&'de [u8], FitObject)> {
let (input, crc) = le_u16(input).map_err(|e| self.to_parse_err(e))?;
self.position += 2;
if !self.options.contains(&DecodeOption::SkipDataCrcValidation) && crc != self.crc {
return Err(Box::new(ErrorKind::InvalidCrc((
Vec::from(input),
FitObject::Crc(crc),
crc,
self.crc,
))));
}
Ok((input, FitObject::Crc(crc)))
}
fn deserialize_message<'de>(
&mut self,
input: &'de [u8],
developer_fields: &HashMap<(u8, u8), DeveloperFieldDescription>,
) -> Result<(&'de [u8], FitObject)> {
let init_len = input.len();
let (remaining, message) = parser::fit_message(input, &self.definitions, developer_fields)
.map_err(|e| self.to_parse_err(e))?;
self.crc = update_crc(self.crc, &input[0..(input.len() - remaining.len())]);
match message {
parser::FitMessage::Data(message) => {
self.position += init_len - remaining.len();
Ok((remaining, FitObject::DataMessage(message)))
}
parser::FitMessage::Definition(message) => {
let msg_rc = Arc::new(message);
self.definitions
.insert(msg_rc.local_message_number(), Arc::clone(&msg_rc));
self.position += init_len - remaining.len();
Ok((remaining, FitObject::DefinitionMessage(msg_rc)))
}
parser::FitMessage::MissingDefinitionMessage(n) => {
Err(ErrorKind::MissingDefinitionMessage(n, self.position).into())
}
}
}
fn to_parse_err(&self, err: nom::Err<nom::error::Error<&[u8]>>) -> crate::Error {
match err {
nom::Err::Error(inner_err) => {
ErrorKind::ParseError(self.position, inner_err.code).into()
}
nom::Err::Failure(inner_err) => {
ErrorKind::ParseError(self.position, inner_err.code).into()
}
nom::Err::Incomplete(needed) => ErrorKind::UnexpectedEof(needed).into(),
}
}
}
pub struct FitStreamProcessor {
decoder: Decoder,
deserializer: Deserializer,
}
impl Default for FitStreamProcessor {
fn default() -> Self {
FitStreamProcessor {
decoder: Decoder::new(),
deserializer: Deserializer::new(),
}
}
}
impl FitStreamProcessor {
pub fn new() -> Self {
Self::default()
}
pub fn add_option(&mut self, opt: DecodeOption) {
self.deserializer.options_mut().insert(opt);
}
pub fn remove_option(&mut self, opt: DecodeOption) {
self.deserializer.options_mut().remove(&opt);
}
pub fn options(&self) -> &HashSet<DecodeOption> {
self.deserializer.options()
}
pub fn reset(&mut self) {
self.decoder.reset();
self.deserializer.reset();
}
pub fn deserialize_next<'de>(&mut self, input: &'de [u8]) -> Result<(&'de [u8], FitObject)> {
self.deserializer
.deserialize_next(input, self.decoder.developer_field_descriptions())
}
pub fn decode_message(&mut self, msg: FitDataMessage) -> Result<FitDataRecord> {
self.decoder
.decode_message(msg, self.deserializer.options())
}
}
pub fn from_bytes_with_options(
mut buffer: &[u8],
options: &HashSet<DecodeOption>,
) -> Result<Vec<FitDataRecord>> {
let mut processor = FitStreamProcessor::new();
let mut records = Vec::new();
options.iter().for_each(|o| processor.add_option(*o));
while !buffer.is_empty() {
let (buf, obj) = processor.deserialize_next(buffer)?;
match obj {
FitObject::Crc(..) => processor.reset(),
FitObject::Header(..) => {}
FitObject::DataMessage(msg) => {
let rec = processor.decode_message(msg)?;
if processor
.options()
.contains(&DecodeOption::DropUnknownMessages)
{
if MesgNum::is_named_variant(rec.kind().as_i64()) {
records.push(rec);
}
} else {
records.push(rec);
}
}
FitObject::DefinitionMessage(..) => {}
}
buffer = buf;
}
Ok(records)
}
pub fn from_bytes(buffer: &[u8]) -> Result<Vec<FitDataRecord>> {
from_bytes_with_options(buffer, &HashSet::new())
}
pub fn from_reader_with_options<T: Read>(
source: &mut T,
options: &HashSet<DecodeOption>,
) -> Result<Vec<FitDataRecord>> {
let mut buffer = Vec::new();
source.read_to_end(&mut buffer)?;
from_bytes_with_options(&buffer, options)
}
pub fn from_reader<T: Read>(source: &mut T) -> Result<Vec<FitDataRecord>> {
from_reader_with_options(source, &HashSet::new())
}