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 717a8ee
Showing 1 changed file with 33 additions and 17 deletions.
50 changes: 33 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 @@ -314,21 +319,31 @@ def _read_lead_in(self, file, segment_position, is_index_file=False):
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 = self._data_file_size
else:
next_segment_pos = (
segment_position + next_segment_offset + lead_size)
if self._data_file_size is not None and next_segment_pos > self._data_file_size:
# The raw data offset is incorrect, and there is less data than expected in this segment
next_segment_pos = self._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 +361,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 +517,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 717a8ee

Please sign in to comment.