Rev 2487: Start implementing the decompressor. in http://bzr.arbash-meinel.com/branches/bzr/0.17-dev/gzip_reader

John Arbash Meinel john at arbash-meinel.com
Wed May 9 05:38:49 BST 2007


At http://bzr.arbash-meinel.com/branches/bzr/0.17-dev/gzip_reader

------------------------------------------------------------
revno: 2487
revision-id: john at arbash-meinel.com-20070509043821-utn042iu0k4xyojw
parent: john at arbash-meinel.com-20070509034259-oh6x2egsagzsl4ww
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: gzip_reader
timestamp: Tue 2007-05-08 23:38:21 -0500
message:
  Start implementing the decompressor.
modified:
  bzrlib/tests/test_tuned_gzip.py test_tuned_gzip.py-20060418042056-c576dfc708984968
  bzrlib/tuned_gzip.py           tuned_gzip.py-20060407014720-5aadc518e928e8d2
-------------- next part --------------
=== modified file 'bzrlib/tests/test_tuned_gzip.py'
--- a/bzrlib/tests/test_tuned_gzip.py	2007-05-09 03:42:59 +0000
+++ b/bzrlib/tests/test_tuned_gzip.py	2007-05-09 04:38:21 +0000
@@ -129,7 +129,7 @@
         self.assertCompressed('\xff\xff\xff\xff')
 
     def test_compress_long_strings(self):
-        self.assertCompressed('abcdefghijklmnopqrstuvwxyz'*1000)
+        self.assertCompressed('abcdefghijklmnopqrstuvwxyz'*10000)
 
 
 class TestDecompressGzipHunk(tests.TestCase):
@@ -154,10 +154,21 @@
         self.assertEqual(plain_text, measured)
 
     def test_decompress_empty_string(self):
-        self.assertDecompress('', '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff'
+        self.assertDecompress('', '')
+        self.assertDecompress('', '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff'
+                                  '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        self.assertDecompress('', '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff'
+                                  '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+                                  '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff'
                                   '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
 
     def test_decompress_simple_strings(self):
+        self.assertDecompress('a',
+            '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+            'K\x04\x00'         # zlib
+            'C\xbe\xb7\xe8'     # crc32
+            '\x01\x00\x00\x00'  # size
+            )
         self.assertCompressDecompress('a')
         self.assertCompressDecompress('b')
         self.assertCompressDecompress('ab')
@@ -173,4 +184,108 @@
         self.assertCompressDecompress('\xff\xff\xff\xff')
 
     def test_decompress_long_strings(self):
-        self.assertCompressDecompress('abcdefghijklmnopqrstuvwxyz'*1000)
+        self.assertCompressDecompress('abcdefghijklmnopqrstuvwxyz'*10000)
+
+    def test_decompress_multiple_hunks(self):
+        self.assertDecompress('aa',
+            '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+            'K\x04\x00'         # zlib
+            'C\xbe\xb7\xe8'     # crc32
+            '\x01\x00\x00\x00'  # size
+            '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+            'K\x04\x00'         # zlib
+            'C\xbe\xb7\xe8'     # crc32
+            '\x01\x00\x00\x00'  # size
+            )
+
+    # TODO: Test that decompress_gzip_hunk supports the extra flags in the gzip
+    # header. FEXTRA, FCOMMENT, FNAME, FHCRC
+
+    def test_decompress_not_a_gzip_string(self):
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x0f\x8b\x08\x00\x00\x00\x00\x00\x02\xff'
+                          '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1e\x8b\x08\x00\x00\x00\x00\x00\x02\xff'
+                          '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x7b\x08\x00\x00\x00\x00\x00\x02\xff'
+                          '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8c\x08\x00\x00\x00\x00\x00\x02\xff'
+                          '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+
+    def test_decompress_unknown_compression(self):
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x00\x00\x00\x00\x00\x00\x02\xff'
+                          '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x07\x00\x00\x00\x00\x00\x02\xff'
+                          '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x09\x00\x00\x00\x00\x00\x02\xff'
+                          '\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+
+    def test_decompress_invalid_crc32(self):
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x10\x00\x00\x00'  # crc32
+                          '\x00\x00\x00\x00') # size
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x03\x00\x00\x00'  # crc32
+                          '\x00\x00\x00\x00') # size
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x50\x00\x00'  # crc32
+                          '\x00\x00\x00\x00') # size
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x07\x00\x00'  # crc32
+                          '\x00\x00\x00\x00') # size
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x00\x90\x00'  # crc32
+                          '\x00\x00\x00\x00') # size
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x00\x0b\x00'  # crc32
+                          '\x00\x00\x00\x00') # size
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x00\x00\xd0'  # crc32
+                          '\x00\x00\x00\x00') # size
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x00\x00\x0f'  # crc32
+                          '\x00\x00\x00\x00') # size
+
+    def test_decompress_invalid_size(self):
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x00\x00\x00'  # crc32
+                          '\xe0\x00\x00\x00') # size
+
+    def test_decompress_invalid_tail(self):
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x00\x00\x00'  # crc32
+                          '\xe0\x00\x00')     # size
+
+    def test_decompress_invalid_extra(self):
+        self.assertRaises(IOError, tuned_gzip.decompress_gzip_hunk,
+                          '\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff' # header
+                          '\x03\x00'          # zlib
+                          '\x00\x00\x00\x00'  # crc32
+                          '\xe0\x00\x00\x00'  # size
+                          '\x00')             # extra

=== modified file 'bzrlib/tuned_gzip.py'
--- a/bzrlib/tuned_gzip.py	2007-05-09 03:42:59 +0000
+++ b/bzrlib/tuned_gzip.py	2007-05-09 04:38:21 +0000
@@ -366,4 +366,43 @@
     :param hunk: A Python str containing a gzipped section.
     :return: A Python str containg the uncompressed text.
     """
-    return GzipFile(mode='rb', fileobj=StringIO(hunk)).read()
+    to_return = []
+    remaining = hunk
+    while len(remaining) > 10:
+        magic = remaining[0:2]
+        if magic != '\037\213':
+            raise IOError('Not a gzipped file')
+        method = ord(remaining[2:3])
+        if method != 8:
+            raise IOError('Unknown compression method')
+        flag = ord(remaining[3:4])
+        # modtime = self.fileobj.read(4) (remaining [4:8])
+        # extraflag = self.fileobj.read(1) (remaining[8:9])
+        # os = self.fileobj.read(1) (remaining[9:10])
+
+        # TODO: handle the flags field
+
+        remaining = remaining[10:]
+
+        crc = zlib.crc32('')
+        decompressor = zlib.decompressobj(-zlib.MAX_WBITS)
+        text = decompressor.decompress(remaining)
+        to_return.append(text)
+        crc = zlib.crc32(text, crc)
+        remaining = decompressor.unused_data
+        if len(remaining) < 8:
+            raise IOError('invalid gzip trailer, no crc or size')
+        # The next 8 bytes should be the crc and file size
+        crc32, isize = struct.unpack("<LL", remaining[:8])
+        remaining = remaining[8:]
+        size = len(text)
+        if crc32 != U32(crc):
+            raise IOError("CRC check failed %d %d" % (crc32, U32(crc)))
+        elif isize != LOWU32(size):
+            raise IOError("Incorrect length of data produced %s != %s"
+                           % (isize, size))
+
+    if len(remaining) > 0:
+        raise IOError('unused trailing bytes')
+
+    return ''.join(to_return)



More information about the bazaar-commits mailing list