| 1 | #!/usr/bin/python2.6 |
|---|
| 2 | |
|---|
| 3 | """ |
|---|
| 4 | Read a compressed file as created by 'lzop' from stdin and write a table to |
|---|
| 5 | stdout containing the blocksize and the start offset (in bytes) of each |
|---|
| 6 | compressed block. |
|---|
| 7 | |
|---|
| 8 | usage: %prog < FILENAME.lzo > FILENAME.lzot |
|---|
| 9 | """ |
|---|
| 10 | |
|---|
| 11 | import struct, sys |
|---|
| 12 | |
|---|
| 13 | MAGIC="\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a" |
|---|
| 14 | |
|---|
| 15 | F_ADLER32_D = 0x00000001L |
|---|
| 16 | F_ADLER32_C = 0x00000002L |
|---|
| 17 | F_H_EXTRA_FIELD = 0x00000040L |
|---|
| 18 | F_H_GMTDIFF = 0x00000080L |
|---|
| 19 | F_CRC32_D = 0x00000100L |
|---|
| 20 | F_CRC32_C = 0x00000200L |
|---|
| 21 | F_MULTIPART = 0x00000400L |
|---|
| 22 | F_H_FILTER = 0x00000800L |
|---|
| 23 | F_H_CRC32 = 0x00001000L |
|---|
| 24 | |
|---|
| 25 | assert struct.calcsize( "!H" ) == 2 |
|---|
| 26 | assert struct.calcsize( "!I" ) == 4 |
|---|
| 27 | |
|---|
| 28 | class UnpackWrapper( object ): |
|---|
| 29 | def __init__( self, file ): |
|---|
| 30 | self.file = file |
|---|
| 31 | def read( self, amt ): |
|---|
| 32 | return self.file.read( amt ) |
|---|
| 33 | def get( self, fmt ): |
|---|
| 34 | t = struct.unpack( fmt, self.file.read( struct.calcsize( fmt ) ) ) |
|---|
| 35 | return t[0] |
|---|
| 36 | |
|---|
| 37 | def main(): |
|---|
| 38 | f = UnpackWrapper( sys.stdin ) |
|---|
| 39 | # Read header |
|---|
| 40 | magic = f.read(9) |
|---|
| 41 | assert magic == MAGIC, "Not LZOP file" |
|---|
| 42 | version = f.get( "!H" ) |
|---|
| 43 | lib_version = f.get( "!H" ) |
|---|
| 44 | if version >= 0x0940: |
|---|
| 45 | extract_version = f.get( "!H" ) |
|---|
| 46 | method = f.get( "!B" ) |
|---|
| 47 | assert 1 <= method <= 3, "Only LZO compression is currently supported" |
|---|
| 48 | level = f.get( "!B" ) |
|---|
| 49 | flags = f.get( "!I" ) |
|---|
| 50 | assert not( flags & F_H_FILTER ), "LZOP filters not supported" |
|---|
| 51 | has_compressed_crc = ( flags & F_CRC32_C or flags & F_ADLER32_C ) |
|---|
| 52 | has_uncompressed_crc = ( flags & F_CRC32_D or flags & F_ADLER32_D ) |
|---|
| 53 | mode = f.get( "!I" ) |
|---|
| 54 | time = f.get( "!I" ) |
|---|
| 55 | time_offset = f.get( "!I" ) |
|---|
| 56 | fname_len = f.get( "!B" ) |
|---|
| 57 | fname = f.read( fname_len ) |
|---|
| 58 | assert len( fname ) == fname_len, "EOF reading filename" |
|---|
| 59 | header_crc = f.get( "!I" ) |
|---|
| 60 | if ( flags & F_H_EXTRA_FIELD ): |
|---|
| 61 | extra_len = f.get( "!I" ) |
|---|
| 62 | extra = f.read( extra_len ) |
|---|
| 63 | assert len( extra ) == extra_len, "EOF reading extra field" |
|---|
| 64 | # Done with header |
|---|
| 65 | block_size = None |
|---|
| 66 | expect_no_more = False |
|---|
| 67 | # Read blocks |
|---|
| 68 | while 1: |
|---|
| 69 | size = f.get( "!I" ) |
|---|
| 70 | if size == 0: break |
|---|
| 71 | assert not( expect_no_more ), \ |
|---|
| 72 | "Encountered an undersized block that was not the last block" |
|---|
| 73 | if block_size is None: |
|---|
| 74 | print "s", size |
|---|
| 75 | block_size = size |
|---|
| 76 | else: |
|---|
| 77 | if size < block_size: |
|---|
| 78 | expect_no_more = True |
|---|
| 79 | compressed_size = f.get( "!I" ) |
|---|
| 80 | if has_uncompressed_crc: |
|---|
| 81 | crc = f.get( "!I" ) |
|---|
| 82 | if has_compressed_crc: |
|---|
| 83 | compressed_crc = f.get( "!I" ) |
|---|
| 84 | print "o", f.file.tell(), compressed_size, size |
|---|
| 85 | compressed_data = f.read( compressed_size ) |
|---|
| 86 | assert len( compressed_data ) == compressed_size, \ |
|---|
| 87 | "EOF reading compressed data" |
|---|
| 88 | |
|---|
| 89 | if __name__ == "__main__": |
|---|
| 90 | main() |
|---|