]> granicus.if.org Git - python/commitdiff
Issue #21538: The plistlib module now supports loading of binary plist files
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 23 May 2014 13:13:33 +0000 (16:13 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Fri, 23 May 2014 13:13:33 +0000 (16:13 +0300)
when reference or offset size is not a power of two.

Lib/plistlib.py
Lib/test/test_plistlib.py
Misc/NEWS

index dcb0f9ce964419b021b48b6e14abde344e606627..8c148a84363958b38f12378ea6f7dc98cd86f3fa 100644 (file)
@@ -619,10 +619,7 @@ class _BinaryPlistParser:
                 offset_table_offset
             ) = struct.unpack('>6xBBQQQ', trailer)
             self._fp.seek(offset_table_offset)
-            offset_format = '>' + _BINARY_FORMAT[offset_size] * num_objects
-            self._ref_format = _BINARY_FORMAT[self._ref_size]
-            self._object_offsets = struct.unpack(
-                offset_format, self._fp.read(offset_size * num_objects))
+            self._object_offsets = self._read_ints(num_objects, offset_size)
             return self._read_object(self._object_offsets[top_object])
 
         except (OSError, IndexError, struct.error):
@@ -638,9 +635,16 @@ class _BinaryPlistParser:
 
         return tokenL
 
+    def _read_ints(self, n, size):
+        data = self._fp.read(size * n)
+        if size in _BINARY_FORMAT:
+            return struct.unpack('>' + _BINARY_FORMAT[size] * n, data)
+        else:
+            return tuple(int.from_bytes(data[i: i + size], 'big')
+                         for i in range(0, size * n, size))
+
     def _read_refs(self, n):
-        return struct.unpack(
-            '>' + self._ref_format * n, self._fp.read(n * self._ref_size))
+        return self._read_ints(n, self._ref_size)
 
     def _read_object(self, offset):
         """
index bb7cc159b4afee0959a36dbea7ecbc9982d16073..dc2fdf696d7e9d0015b753f47caf84ecf64357f1 100644 (file)
@@ -411,6 +411,18 @@ class TestPlistlib(unittest.TestCase):
                 pl2 = plistlib.loads(data)
                 self.assertEqual(dict(pl), dict(pl2))
 
+    def test_nonstandard_refs_size(self):
+        # Issue #21538: Refs and offsets are 24-bit integers
+        data = (b'bplist00'
+                b'\xd1\x00\x00\x01\x00\x00\x02QaQb'
+                b'\x00\x00\x08\x00\x00\x0f\x00\x00\x11'
+                b'\x00\x00\x00\x00\x00\x00'
+                b'\x03\x03'
+                b'\x00\x00\x00\x00\x00\x00\x00\x03'
+                b'\x00\x00\x00\x00\x00\x00\x00\x00'
+                b'\x00\x00\x00\x00\x00\x00\x00\x13')
+        self.assertEqual(plistlib.loads(data), {'a': 'b'})
+
 
 class TestPlistlibDeprecated(unittest.TestCase):
     def test_io_deprecated(self):
index a32df2e2c80b85f5f6411167443343fed05e67fe..6bee579ba983295cb4d35504e583c3c9db3e6dc7 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -15,6 +15,12 @@ Core and Builtins
   time issue noticeable when compiling code with a large number of "and"
   and "or" operators.
 
+Library
+-------
+
+- Issue #21538: The plistlib module now supports loading of binary plist files
+  when reference or offset size is not a power of two.
+
 Tests
 -----