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