f.setframerate(arg)
self.assertEqual(f.getframerate(), expected)
+ def test_write_odd_data_chunk_pads_and_updates_riff_size(self):
+ # gh-117716: odd-sized data chunks must be padded with one zero byte.
+ with io.BytesIO() as output:
+ with wave.open(output, mode='wb') as w:
+ w.setnchannels(1)
+ w.setsampwidth(1)
+ w.setframerate(48000)
+ w.writeframes(b'\x80')
+
+ value = output.getvalue()
+
+ self.assertEqual(value[-1], 0)
+ self.assertEqual(
+ int.from_bytes(value[4:8], byteorder='little'),
+ 38,
+ )
+
+ with wave.open(io.BytesIO(value), mode='rb') as r:
+ self.assertEqual(r.getnchannels(), 1)
+ self.assertEqual(r.getsampwidth(), 1)
+ self.assertEqual(r.getframerate(), 48000)
+ self.assertEqual(r.getnframes(), 1)
+ self.assertEqual(r.readframes(-1), b'\x80')
+
class WaveOpen(unittest.TestCase):
def test_open_pathlike(self):
try:
if self._file:
self._ensure_header_written(0)
+ if self._datawritten & 1:
+ self._file.write(b'\x00')
if self._datalength != self._datawritten:
self._patchheader()
self._file.flush()
has_fact = self._needs_fact_chunk()
header_overhead = 36 + (12 if has_fact else 0)
self._file.write(struct.pack('<L4s4sLHHLLHH',
- header_overhead + self._datalength, b'WAVE', b'fmt ', 16,
+ header_overhead + self._datalength + (self._datalength & 1), b'WAVE', b'fmt ', 16,
self._format, self._nchannels, self._framerate,
self._nchannels * self._framerate * self._sampwidth,
self._nchannels * self._sampwidth,
curpos = self._file.tell()
header_overhead = 36 + (12 if self._needs_fact_chunk() else 0)
self._file.seek(self._form_length_pos, 0)
- self._file.write(struct.pack('<L', header_overhead + self._datawritten))
+ self._file.write(struct.pack('<L', header_overhead + self._datawritten + (self._datawritten & 1)))
if self._fact_sample_count_pos is not None:
self._file.seek(self._fact_sample_count_pos, 0)
nframes = self._datawritten // (self._nchannels * self._sampwidth)