[Python-checkins] cpython (2.7): Issue #13589: Fix some serialization primitives in the aifc module.

antoine.pitrou python-checkins at python.org
Tue Jan 17 17:19:36 CET 2012


http://hg.python.org/cpython/rev/8fac90d0f4cd
changeset:   74467:8fac90d0f4cd
branch:      2.7
parent:      74463:f2ef537aaf61
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Tue Jan 17 17:13:04 2012 +0100
summary:
  Issue #13589: Fix some serialization primitives in the aifc module.
Patch by Oleg Plakhotnyuk.

files:
  Lib/aifc.py           |  48 +++++++++++++++++++-----------
  Lib/test/test_aifc.py |  38 ++++++++++++++++++++++++
  Misc/ACKS             |   1 +
  Misc/NEWS             |   3 +
  4 files changed, 72 insertions(+), 18 deletions(-)


diff --git a/Lib/aifc.py b/Lib/aifc.py
--- a/Lib/aifc.py
+++ b/Lib/aifc.py
@@ -162,6 +162,12 @@
     except struct.error:
         raise EOFError
 
+def _read_ushort(file):
+    try:
+        return struct.unpack('>H', file.read(2))[0]
+    except struct.error:
+        raise EOFError
+
 def _read_string(file):
     length = ord(file.read(1))
     if length == 0:
@@ -194,13 +200,19 @@
 def _write_short(f, x):
     f.write(struct.pack('>h', x))
 
+def _write_ushort(f, x):
+    f.write(struct.pack('>H', x))
+
 def _write_long(f, x):
+    f.write(struct.pack('>l', x))
+
+def _write_ulong(f, x):
     f.write(struct.pack('>L', x))
 
 def _write_string(f, s):
     if len(s) > 255:
         raise ValueError("string exceeds maximum pstring length")
-    f.write(chr(len(s)))
+    f.write(struct.pack('B', len(s)))
     f.write(s)
     if len(s) & 1 == 0:
         f.write(chr(0))
@@ -218,7 +230,7 @@
         lomant = 0
     else:
         fmant, expon = math.frexp(x)
-        if expon > 16384 or fmant >= 1:     # Infinity or NaN
+        if expon > 16384 or fmant >= 1 or fmant != fmant: # Infinity or NaN
             expon = sign|0x7FFF
             himant = 0
             lomant = 0
@@ -234,9 +246,9 @@
             fmant = math.ldexp(fmant - fsmant, 32)
             fsmant = math.floor(fmant)
             lomant = long(fsmant)
-    _write_short(f, expon)
-    _write_long(f, himant)
-    _write_long(f, lomant)
+    _write_ushort(f, expon)
+    _write_ulong(f, himant)
+    _write_ulong(f, lomant)
 
 from chunk import Chunk
 
@@ -840,15 +852,15 @@
         if self._aifc:
             self._file.write('AIFC')
             self._file.write('FVER')
-            _write_long(self._file, 4)
-            _write_long(self._file, self._version)
+            _write_ulong(self._file, 4)
+            _write_ulong(self._file, self._version)
         else:
             self._file.write('AIFF')
         self._file.write('COMM')
-        _write_long(self._file, commlength)
+        _write_ulong(self._file, commlength)
         _write_short(self._file, self._nchannels)
         self._nframes_pos = self._file.tell()
-        _write_long(self._file, self._nframes)
+        _write_ulong(self._file, self._nframes)
         _write_short(self._file, self._sampwidth * 8)
         _write_float(self._file, self._framerate)
         if self._aifc:
@@ -856,9 +868,9 @@
             _write_string(self._file, self._compname)
         self._file.write('SSND')
         self._ssnd_length_pos = self._file.tell()
-        _write_long(self._file, self._datalength + 8)
-        _write_long(self._file, 0)
-        _write_long(self._file, 0)
+        _write_ulong(self._file, self._datalength + 8)
+        _write_ulong(self._file, 0)
+        _write_ulong(self._file, 0)
 
     def _write_form_length(self, datalength):
         if self._aifc:
@@ -869,8 +881,8 @@
         else:
             commlength = 18
             verslength = 0
-        _write_long(self._file, 4 + verslength + self._marklength + \
-                    8 + commlength + 16 + datalength)
+        _write_ulong(self._file, 4 + verslength + self._marklength + \
+                     8 + commlength + 16 + datalength)
         return commlength
 
     def _patchheader(self):
@@ -888,9 +900,9 @@
         self._file.seek(self._form_length_pos, 0)
         dummy = self._write_form_length(datalength)
         self._file.seek(self._nframes_pos, 0)
-        _write_long(self._file, self._nframeswritten)
+        _write_ulong(self._file, self._nframeswritten)
         self._file.seek(self._ssnd_length_pos, 0)
-        _write_long(self._file, datalength + 8)
+        _write_ulong(self._file, datalength + 8)
         self._file.seek(curpos, 0)
         self._nframes = self._nframeswritten
         self._datalength = datalength
@@ -905,13 +917,13 @@
             length = length + len(name) + 1 + 6
             if len(name) & 1 == 0:
                 length = length + 1
-        _write_long(self._file, length)
+        _write_ulong(self._file, length)
         self._marklength = length + 8
         _write_short(self._file, len(self._markers))
         for marker in self._markers:
             id, pos, name = marker
             _write_short(self._file, id)
-            _write_long(self._file, pos)
+            _write_ulong(self._file, pos)
             _write_string(self._file, name)
 
 def open(f, mode=None):
diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py
--- a/Lib/test/test_aifc.py
+++ b/Lib/test/test_aifc.py
@@ -1,6 +1,7 @@
 from test.test_support import findfile, run_unittest, TESTFN
 import unittest
 import os
+import io
 
 import aifc
 
@@ -107,8 +108,45 @@
         self.assertEqual(testfile.closed, True)
 
 
+class AIFCLowLevelTest(unittest.TestCase):
+
+    def test_read_written(self):
+        def read_written(self, what):
+            f = io.BytesIO()
+            getattr(aifc, '_write_' + what)(f, x)
+            f.seek(0)
+            return getattr(aifc, '_read_' + what)(f)
+        for x in (-1, 0, 0.1, 1):
+            self.assertEqual(read_written(x, 'float'), x)
+        for x in (float('NaN'), float('Inf')):
+            self.assertEqual(read_written(x, 'float'), aifc._HUGE_VAL)
+        for x in (b'', b'foo', b'a' * 255):
+            self.assertEqual(read_written(x, 'string'), x)
+        for x in (-0x7FFFFFFF, -1, 0, 1, 0x7FFFFFFF):
+            self.assertEqual(read_written(x, 'long'), x)
+        for x in (0, 1, 0xFFFFFFFF):
+            self.assertEqual(read_written(x, 'ulong'), x)
+        for x in (-0x7FFF, -1, 0, 1, 0x7FFF):
+            self.assertEqual(read_written(x, 'short'), x)
+        for x in (0, 1, 0xFFFF):
+            self.assertEqual(read_written(x, 'ushort'), x)
+
+    def test_read_raises(self):
+        f = io.BytesIO(b'\x00')
+        self.assertRaises(EOFError, aifc._read_ulong, f)
+        self.assertRaises(EOFError, aifc._read_long, f)
+        self.assertRaises(EOFError, aifc._read_ushort, f)
+        self.assertRaises(EOFError, aifc._read_short, f)
+
+    def test_write_long_string_raises(self):
+        f = io.BytesIO()
+        with self.assertRaises(ValueError):
+            aifc._write_string(f, b'too long' * 255)
+
+
 def test_main():
     run_unittest(AIFCTest)
+    run_unittest(AIFCLowLevelTest)
 
 
 if __name__ == "__main__":
diff --git a/Misc/ACKS b/Misc/ACKS
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -662,6 +662,7 @@
 Michael Piotrowski
 Antoine Pitrou
 Jean-François Piéronne
+Oleg Plakhotnyuk
 Guilherme Polo
 Michael Pomraning
 Iustin Pop
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -89,6 +89,9 @@
 Library
 -------
 
+- Issue #13589: Fix some serialization primitives in the aifc module.
+  Patch by Oleg Plakhotnyuk.
+
 - Issue #13642: Unquote before b64encoding user:password during Basic
   Authentication. Patch contributed by Joonas Kuorilehto and Michele Orrù.
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list