Skip to content

Commit e39980a

Browse files
committed
Add support for chained fit files
From the SDK: > The FIT protocol allows for multiple FIT files to be chained together > in a single FIT file. Each FIT file in the chain must be a properly > formatted FIT file (header, data records, CRC). The implementation is to note the total filesize when first loading the file, then check if there's more data after we finish processing the number of bytes the initial header specifies. If there is more data, try to parse it as a fit header, then continue as normal.
1 parent 9473218 commit e39980a

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

fitparse/base.py

+23-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import io
2+
import os
23
import struct
34

45
from fitparse.processors import FitFileDataProcessor
@@ -25,17 +26,14 @@ def __init__(self, fileish, check_crc=True, data_processor=None):
2526
self._file = open(fileish, 'rb')
2627

2728
self.check_crc = check_crc
28-
29-
self._accumulators = {}
30-
self._bytes_left = -1 # Not valid until after _parse_file_header()
31-
self._complete = False
32-
self._compressed_ts_accumulator = 0
33-
self._crc = 0
34-
self._local_mesgs = {}
35-
self._messages = []
3629
self._processor = data_processor or FitFileDataProcessor()
3730

38-
# Start off by parsing the file header (makes self._bytes_left valid)
31+
# Get total filesize
32+
self._file.seek(0, os.SEEK_END)
33+
self._filesize = self._file.tell()
34+
self._file.seek(0, os.SEEK_SET)
35+
36+
# Start off by parsing the file header (sets initial attribute values)
3937
self._parse_file_header()
4038

4139
def __del__(self):
@@ -89,6 +87,16 @@ def _read_and_assert_crc(self, allow_zero=False):
8987
# Private Data Parsing Methods
9088

9189
def _parse_file_header(self):
90+
91+
# Initialize data
92+
self._accumulators = {}
93+
self._bytes_left = -1
94+
self._complete = False
95+
self._compressed_ts_accumulator = 0
96+
self._crc = 0
97+
self._local_mesgs = {}
98+
self._messages = []
99+
92100
header_data = self._read(12)
93101
if header_data[8:12] != b'.FIT':
94102
raise FitParseError("Invalid .FIT File Header")
@@ -122,10 +130,15 @@ def _parse_message(self):
122130
if self._bytes_left <= 0:
123131
if not self._complete:
124132
self._read_and_assert_crc()
133+
134+
if self._file.tell() >= self._filesize:
125135
self._complete = True
126136
self.close()
137+
return None
127138

128-
return None
139+
# Still have data left in the file - assuming chained fit files
140+
self._parse_file_header()
141+
return self._parse_message()
129142

130143
header = self._parse_message_header()
131144

0 commit comments

Comments
 (0)