Skip to content

Commit

Permalink
Handle when the next segment offset is set but is beyond the end of t…
Browse files Browse the repository at this point in the history
…he file
  • Loading branch information
adamreeve committed Feb 18, 2024
1 parent 662c35b commit ea0cdca
Showing 1 changed file with 34 additions and 17 deletions.
51 changes: 34 additions & 17 deletions nptdms/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ def __init__(self, tdms_file):
self._index_file_path = filepath
self._index_file = open(self._index_file_path, "rb")

if self._file is not None:
self._data_file_size = _get_file_size(self._file)
else:
self._data_file_size = None

def close(self):
if self._file is None and self._index_file is None:
# Already closed
Expand Down Expand Up @@ -311,24 +316,35 @@ def _read_lead_in(self, file, segment_position, is_index_file=False):
# Calculate data and next segment position
lead_size = 7 * 4
data_position = segment_position + lead_size + raw_data_offset
data_file_size = self._data_file_size
segment_incomplete = next_segment_offset == 0xFFFFFFFFFFFFFFFF
if segment_incomplete:
# Segment size is unknown. This can happen if LabVIEW crashes.
next_segment_pos = self._get_data_file_size()
next_segment_pos = data_file_size
else:
next_segment_pos = (
segment_position + next_segment_offset + lead_size)
if data_file_size is not None and next_segment_pos > data_file_size:
# The raw data offset is incorrect, and there is less data than expected in this segment
next_segment_pos = data_file_size
segment_incomplete = True

if segment_incomplete:
if next_segment_pos < data_position:
# Metadata wasn't completely written and don't have any data in this segment,
# don't try to read any metadata
log.warning("Last segment metadata is incomplete")
raise EOFError
# Try to read until the end of the file if we have complete metadata
log.warning(
"Last segment of file has unknown size, "
"will attempt to read to the end of the file")
else:
log.debug("Next segment offset = %d, raw data offset = %d, data size = %d b",
next_segment_offset, raw_data_offset, next_segment_offset - raw_data_offset)
next_segment_pos = (
segment_position + next_segment_offset + lead_size)
else:
# Try to read until the end of the file if we have complete metadata
log.warning(
"Last segment of file has less data than expected, "
"will attempt to read to the end of the file")

log.debug("Next segment offset = %d, raw data offset = %d, expected data size = %d b, actual data size = %d b",
next_segment_offset, raw_data_offset,
next_segment_offset - raw_data_offset,
next_segment_pos - data_position)

return segment_position, toc_mask, data_position, next_segment_pos, segment_incomplete

Expand All @@ -346,13 +362,6 @@ def _verify_segment_start(self, segment):
position) +
"Check that the tdms_index file matches the tdms data file.")

def _get_data_file_size(self):
current_pos = self._file.tell()
self._file.seek(0, os.SEEK_END)
end_pos = self._file.tell()
self._file.seek(current_pos, os.SEEK_SET)
return end_pos

def _update_object_metadata(self, segment):
""" Update object metadata using the metadata read from a single segment
"""
Expand Down Expand Up @@ -509,3 +518,11 @@ def _array_equal(a, b, chunk_size=100):
if not (a[offset:offset+chunk_size] == b[offset:offset+chunk_size]).all():
return False
return True


def _get_file_size(file):
current_pos = file.tell()
file.seek(0, os.SEEK_END)
end_pos = file.tell()
file.seek(current_pos, os.SEEK_SET)
return end_pos

0 comments on commit ea0cdca

Please sign in to comment.