diff --git a/Lib/aifc.py b/Lib/aifc.py index d8b7fab7dab..9ac710fbde5 100644 --- a/Lib/aifc.py +++ b/Lib/aifc.py @@ -778,7 +778,7 @@ class Aifc_write: def _ensure_header_written(self, datasize): if not self._nframeswritten: - if self._comptype in ('ULAW', 'ALAW'): + if self._comptype in ('ULAW', 'ulaw', 'ALAW', 'alaw'): if not self._sampwidth: self._sampwidth = 2 if self._sampwidth != 2: @@ -844,7 +844,7 @@ class Aifc_write: if self._datalength & 1: self._datalength = self._datalength + 1 if self._aifc: - if self._comptype in ('ULAW', 'ALAW'): + if self._comptype in ('ULAW', 'ulaw', 'ALAW', 'alaw'): self._datalength = self._datalength // 2 if self._datalength & 1: self._datalength = self._datalength + 1 @@ -852,7 +852,10 @@ class Aifc_write: self._datalength = (self._datalength + 3) // 4 if self._datalength & 1: self._datalength = self._datalength + 1 - self._form_length_pos = self._file.tell() + try: + self._form_length_pos = self._file.tell() + except (AttributeError, IOError): + self._form_length_pos = None commlength = self._write_form_length(self._datalength) if self._aifc: self._file.write('AIFC') @@ -864,7 +867,8 @@ class Aifc_write: self._file.write('COMM') _write_ulong(self._file, commlength) _write_short(self._file, self._nchannels) - self._nframes_pos = self._file.tell() + if self._form_length_pos is not None: + self._nframes_pos = self._file.tell() _write_ulong(self._file, self._nframes) if self._comptype in ('ULAW', 'ulaw', 'ALAW', 'alaw', 'G722'): _write_short(self._file, 8) @@ -875,7 +879,8 @@ class Aifc_write: self._file.write(self._comptype) _write_string(self._file, self._compname) self._file.write('SSND') - self._ssnd_length_pos = self._file.tell() + if self._form_length_pos is not None: + self._ssnd_length_pos = self._file.tell() _write_ulong(self._file, self._datalength + 8) _write_ulong(self._file, 0) _write_ulong(self._file, 0) diff --git a/Lib/test/audiotests.py b/Lib/test/audiotests.py index e378277b6bc..93576e6a9ce 100644 --- a/Lib/test/audiotests.py +++ b/Lib/test/audiotests.py @@ -6,6 +6,13 @@ import pickle import sys import base64 +class UnseekableIO(io.FileIO): + def tell(self): + raise io.UnsupportedOperation + + def seek(self, *args, **kwargs): + raise io.UnsupportedOperation + def fromhex(s): return base64.b16decode(s.replace(' ', '')) @@ -133,6 +140,62 @@ class AudioWriteTests(AudioTests): self.assertEqual(testfile.read(13), b'ababagalamaga') self.check_file(testfile, self.nframes, self.frames) + def test_unseekable_read(self): + f = self.create_file(TESTFN) + f.setnframes(self.nframes) + f.writeframes(self.frames) + f.close() + + with UnseekableIO(TESTFN, 'rb') as testfile: + self.check_file(testfile, self.nframes, self.frames) + + def test_unseekable_write(self): + with UnseekableIO(TESTFN, 'wb') as testfile: + f = self.create_file(testfile) + f.setnframes(self.nframes) + f.writeframes(self.frames) + f.close() + self.fout = None + + self.check_file(TESTFN, self.nframes, self.frames) + + def test_unseekable_incompleted_write(self): + with UnseekableIO(TESTFN, 'wb') as testfile: + testfile.write(b'ababagalamaga') + f = self.create_file(testfile) + f.setnframes(self.nframes + 1) + try: + f.writeframes(self.frames) + except IOError: + pass + try: + f.close() + except IOError: + pass + + with open(TESTFN, 'rb') as testfile: + self.assertEqual(testfile.read(13), b'ababagalamaga') + self.check_file(testfile, self.nframes + 1, self.frames) + + def test_unseekable_overflowed_write(self): + with UnseekableIO(TESTFN, 'wb') as testfile: + testfile.write(b'ababagalamaga') + f = self.create_file(testfile) + f.setnframes(self.nframes - 1) + try: + f.writeframes(self.frames) + except IOError: + pass + try: + f.close() + except IOError: + pass + + with open(TESTFN, 'rb') as testfile: + self.assertEqual(testfile.read(13), b'ababagalamaga') + framesize = self.nchannels * self.sampwidth + self.check_file(testfile, self.nframes - 1, self.frames[:-framesize]) + class AudioTestsWithSourceFile(AudioTests): diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py index a312d31b9e5..cfc491db21c 100644 --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -9,10 +9,14 @@ import struct import aifc -class AifcPCM8Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): +class AifcTest(audiotests.AudioWriteTests, + audiotests.AudioTestsWithSourceFile): module = aifc + close_fd = True + test_unseekable_read = None + + +class AifcPCM8Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm8.aiff' sndfilenframes = 3307 nchannels = 2 @@ -27,13 +31,9 @@ class AifcPCM8Test(audiotests.AudioWriteTests, 11FA 3EFB BCFC 66FF CF04 4309 C10E 5112 EE17 8216 7F14 8012 \ 490E 520D EF0F CE0F E40C 630A 080A 2B0B 510E 8B11 B60E 440A \ """) - close_fd = True -class AifcPCM16Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcPCM16Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm16.aiff' sndfilenframes = 3307 nchannels = 2 @@ -50,13 +50,9 @@ class AifcPCM16Test(audiotests.AudioWriteTests, EEE21753 82071665 7FFF1443 8004128F 49A20EAF 52BB0DBA EFB40F60 CE3C0FBF \ E4B30CEC 63430A5C 08C80A20 2BBB0B08 514A0E43 8BCF1139 B6F60EEB 44120A5E \ """) - close_fd = True -class AifcPCM24Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcPCM24Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm24.aiff' sndfilenframes = 3307 nchannels = 2 @@ -79,13 +75,9 @@ class AifcPCM24Test(audiotests.AudioWriteTests, E4B49C0CEA2D 6344A80A5A7C 08C8FE0A1FFE 2BB9860B0A0E \ 51486F0E44E1 8BCC64113B05 B6F4EC0EEB36 4413170A5B48 \ """) - close_fd = True -class AifcPCM32Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcPCM32Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm32.aiff' sndfilenframes = 3307 nchannels = 2 @@ -108,13 +100,9 @@ class AifcPCM32Test(audiotests.AudioWriteTests, E4B49CC00CEA2D90 6344A8800A5A7CA0 08C8FE800A1FFEE0 2BB986C00B0A0E00 \ 51486F800E44E190 8BCC6480113B0580 B6F4EC000EEB3630 441317800A5B48A0 \ """) - close_fd = True -class AifcULAWTest(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcULAWTest(AifcTest, unittest.TestCase): sndfilename = 'pluck-ulaw.aifc' sndfilenframes = 3307 nchannels = 2 @@ -133,7 +121,6 @@ class AifcULAWTest(audiotests.AudioWriteTests, """) if sys.byteorder != 'big': frames = audiotests.byteswap2(frames) - close_fd = True class AifcMiscTest(audiotests.AudioTests, unittest.TestCase): diff --git a/Lib/test/test_sunau.py b/Lib/test/test_sunau.py index 64cbebdcfb1..f6828683521 100644 --- a/Lib/test/test_sunau.py +++ b/Lib/test/test_sunau.py @@ -5,10 +5,12 @@ import sys import sunau -class SunauPCM8Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): +class SunauTest(audiotests.AudioWriteTests, + audiotests.AudioTestsWithSourceFile): module = sunau + + +class SunauPCM8Test(SunauTest, unittest.TestCase): sndfilename = 'pluck-pcm8.au' sndfilenframes = 3307 nchannels = 2 @@ -25,10 +27,7 @@ class SunauPCM8Test(audiotests.AudioWriteTests, """) -class SunauPCM16Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = sunau +class SunauPCM16Test(SunauTest, unittest.TestCase): sndfilename = 'pluck-pcm16.au' sndfilenframes = 3307 nchannels = 2 @@ -47,10 +46,7 @@ class SunauPCM16Test(audiotests.AudioWriteTests, """) -class SunauPCM32Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = sunau +class SunauPCM32Test(SunauTest, unittest.TestCase): sndfilename = 'pluck-pcm32.au' sndfilenframes = 3307 nchannels = 2 @@ -75,10 +71,7 @@ class SunauPCM32Test(audiotests.AudioWriteTests, """) -class SunauULAWTest(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = sunau +class SunauULAWTest(SunauTest, unittest.TestCase): sndfilename = 'pluck-ulaw.au' sndfilenframes = 3307 nchannels = 2 diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 3e8ef5123b2..9513df45938 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -5,10 +5,15 @@ import sys import wave -class WavePCM8Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): +class WaveTest(audiotests.AudioWriteTests, + audiotests.AudioTestsWithSourceFile): module = wave + test_unseekable_write = None + test_unseekable_overflowed_write = None + test_unseekable_incompleted_write = None + + +class WavePCM8Test(WaveTest, unittest.TestCase): sndfilename = 'pluck-pcm8.wav' sndfilenframes = 3307 nchannels = 2 @@ -25,10 +30,7 @@ class WavePCM8Test(audiotests.AudioWriteTests, """) -class WavePCM16Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = wave +class WavePCM16Test(WaveTest, unittest.TestCase): sndfilename = 'pluck-pcm16.wav' sndfilenframes = 3307 nchannels = 2 @@ -55,10 +57,7 @@ class WavePCM16Test(audiotests.AudioWriteTests, -class WavePCM24Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = wave +class WavePCM24Test(WaveTest, unittest.TestCase): sndfilename = 'pluck-pcm24.wav' sndfilenframes = 3307 nchannels = 2 @@ -85,10 +84,7 @@ class WavePCM24Test(audiotests.AudioWriteTests, frames = audiotests.byteswap3(frames) -class WavePCM32Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = wave +class WavePCM32Test(WaveTest, unittest.TestCase): sndfilename = 'pluck-pcm32.wav' sndfilenframes = 3307 nchannels = 2 diff --git a/Misc/NEWS b/Misc/NEWS index 327c3d78429..3c9481417e6 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -23,6 +23,9 @@ Core and Builtins Library ------- +- Issue #19623: Fixed writing to unseekable files in the aifc module. + Fixed writing 'ulaw' (lower case) compressed AIFC files. + - Issue #17919: select.poll.register() again works with poll.POLLNVAL on AIX. Fixed integer overflow in the eventmask parameter.