Skip to content

Commit 9861f51

Browse files
author
Benjamin Moody
committed
Merge pull request #2 into main
2 parents a17a016 + 96481a4 commit 9861f51

2 files changed

Lines changed: 51 additions & 1 deletion

File tree

‎src/plibflac/_decoder.py‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ def open(self):
130130
has already been opened, this method does nothing.
131131
"""
132132
if not self._opened:
133+
self._original_raw_pos = None
133134
try:
134135
if isinstance(self._fileobj, io.FileIO):
135136
fd = self._fileobj.fileno()
@@ -138,7 +139,12 @@ def open(self):
138139
and isinstance(self._fileobj.raw, io.FileIO)
139140
and self._fileobj.seekable()):
140141
fd = self._fileobj.fileno()
141-
self._fileobj.seek(0, io.SEEK_CUR)
142+
# Set the raw stream position (where we will begin
143+
# decoding) to the current buffered stream
144+
# position. Save the original raw stream position
145+
# for later use.
146+
self._original_raw_pos = self._fileobj.raw.tell()
147+
self._fileobj.raw.seek(self._fileobj.tell())
142148
else:
143149
fd = -1
144150
except OSError:
@@ -168,6 +174,16 @@ def close(self):
168174
if self._opened:
169175
self._opened = False
170176
self._decoder.close()
177+
if self._original_raw_pos is not None:
178+
# Set the buffered stream position equal to the
179+
# current raw stream position (where we finished
180+
# decoding). In order to ensure the internal
181+
# state of the BufferedReader is consistent, we
182+
# must first restore the raw stream to the
183+
# position it had originally.
184+
final_pos = self._fileobj.raw.tell()
185+
self._fileobj.raw.seek(self._original_raw_pos)
186+
self._fileobj.seek(final_pos)
171187
finally:
172188
if self._closefile:
173189
self._closefile = False

‎tests/test_decoder.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,40 @@ def test_read_fileobj(self):
5454
with plibflac.Decoder(fileobj) as decoder:
5555
self._test_read_sequential(decoder)
5656

57+
def test_read_buffered(self):
58+
"""
59+
Test reading from a buffered file object.
60+
"""
61+
with open(self.data_path('100s.flac'), 'rb') as fileobj:
62+
# Read the first few bytes of the file, then rewind.
63+
# Decoder should start reading at the current position in
64+
# the buffered stream, not at the underlying file
65+
# descriptor position.
66+
fileobj.read(50)
67+
fileobj.seek(0)
68+
with plibflac.Decoder(fileobj) as decoder:
69+
self._test_read_sequential(decoder)
70+
71+
with open(self.data_path('100s.flac'), 'rb') as fileobj:
72+
# Check that buffered file object is correctly
73+
# resynchronized after the decoder is closed.
74+
fileobj.read(50)
75+
fileobj.seek(0)
76+
with plibflac.Decoder(fileobj) as decoder:
77+
decoder.read(5000)
78+
next_pos1 = fileobj.tell()
79+
next_bytes1 = fileobj.read(100)
80+
81+
fileobj = fileobj.raw
82+
fileobj.seek(0)
83+
with plibflac.Decoder(fileobj) as decoder:
84+
decoder.read(5000)
85+
next_pos2 = fileobj.tell()
86+
next_bytes2 = fileobj.read(100)
87+
88+
self.assertEqual(next_pos1, next_pos2)
89+
self.assertEqual(next_bytes1, next_bytes2)
90+
5791
def test_read_bytesio(self):
5892
"""
5993
Test reading from a BytesIO object.

0 commit comments

Comments
 (0)