fromBytes static method
FitFile
fromBytes(
- Uint8List bytes, {
- dynamic checkCrc = true,
- dynamic checkRecords = false,
})
Implementation
static FitFile fromBytes(Uint8List bytes,
{checkCrc = true, checkRecords = false}) {
var byteOffset = 0;
var crc = 0;
final headerSize = bytes[0];
final headerBytes =
Uint8List.sublistView(bytes, byteOffset, byteOffset + headerSize);
final header = FitFileHeader.fromBytes(headerBytes);
crc = crc16(headerBytes, initial: crc);
byteOffset += header.size;
final records = <Record>[];
final definitionMessageMap = <int, DefinitionMessage>{};
final developerFieldsById = <int, Map<int, DeveloperField>>{};
var recordIndex = 0;
var recordBytesRemainingCount = header.recordsSize;
while (recordBytesRemainingCount > 0) {
// print('Record $recordIndex');
final remainingBytes = Uint8List.sublistView(bytes, byteOffset);
final record = Record.fromBytes(definitionMessageMap, remainingBytes,
developerFieldsById: developerFieldsById);
if (record.isDefinition) {
definitionMessageMap[record.localId] =
record.message as DefinitionMessage;
} else if (record.message is FieldDescriptionMessage) {
final message = record.message as FieldDescriptionMessage;
//TODO(mkt): more work is needed here for more complicated dynamic fields.
final developerField = DeveloperField(
developerDataIndex: message.developerDataIndex ?? 0,
id: message.fieldDefinitionNumber ?? 0,
name: message.name,
type: BaseTypeExtension.fromValue(message.fitBaseTypeId ?? 0),
scale: message.scale?.toDouble(),
offset: message.offset?.toDouble(),
units: message.units ?? '',
);
if (developerFieldsById[developerField.developerDataIndex] == null) {
developerFieldsById[developerField.developerDataIndex] = {};
}
developerFieldsById[developerField.developerDataIndex]![
developerField.id] = developerField;
}
records.add(record);
final definitionMessage = definitionMessageMap[record.localId];
final recordSize = record.size;
final definedSize = record.definedSize(definitionMessage!);
crc = crc16(
Uint8List.sublistView(bytes, byteOffset, byteOffset + definedSize),
initial: crc);
if (recordSize != definedSize) {
logger.w(
'Record $recordIndex, ${record.message}: size ($recordSize) != defined size ($definedSize). Some fields were not read correctly.');
}
if (checkRecords) {
final actualBytes =
Uint8List.sublistView(remainingBytes, 0, definedSize);
final recordBytes = record.toBytes();
if (!listEqual(actualBytes, recordBytes)) {
logger.w(
'- $recordIndex -\nactual: $actualBytes\nrecord: $recordBytes');
}
}
recordBytesRemainingCount -= definedSize;
byteOffset += definedSize;
recordIndex++;
}
final byteData = ByteData.sublistView(bytes, byteOffset, byteOffset + 2);
final fileCrc = byteData.getUint16(0, Endian.little);
if (crc != fileCrc) {
final message =
'Calculated crc (0x${crc.toRadixString(16)}) does match crc in file (0x${fileCrc.toRadixString(16)}).';
if (checkCrc) {
throw Exception(message);
} else {
logger.w(message);
}
}
return FitFile(header, records, crc);
}