1*5a923131SAndroid Build Coastguard Worker# import mmap 2*5a923131SAndroid Build Coastguard Worker 3*5a923131SAndroid Build Coastguard Workerimport struct 4*5a923131SAndroid Build Coastguard Worker 5*5a923131SAndroid Build Coastguard WorkerLZ4_FRAME_MAGIC = b"\x04\x22\x4D\x18" 6*5a923131SAndroid Build Coastguard Worker 7*5a923131SAndroid Build Coastguard Worker 8*5a923131SAndroid Build Coastguard Workerdef scan_legacy_lz4_frames(data): 9*5a923131SAndroid Build Coastguard Worker LZ4_LEGACY_FRAME_MAGIC = b"\x02\x21\x4C\x18" 10*5a923131SAndroid Build Coastguard Worker index = 0 11*5a923131SAndroid Build Coastguard Worker while index < len(data): 12*5a923131SAndroid Build Coastguard Worker try: 13*5a923131SAndroid Build Coastguard Worker index = data.index(LZ4_LEGACY_FRAME_MAGIC, index) 14*5a923131SAndroid Build Coastguard Worker print("Legacy Lz4 frame at {}".format(index)) 15*5a923131SAndroid Build Coastguard Worker index += 4 16*5a923131SAndroid Build Coastguard Worker while index < len(data): 17*5a923131SAndroid Build Coastguard Worker magic = data[index:index+4] 18*5a923131SAndroid Build Coastguard Worker if magic == LZ4_LEGACY_FRAME_MAGIC or magic == LZ4_FRAME_MAGIC: 19*5a923131SAndroid Build Coastguard Worker break 20*5a923131SAndroid Build Coastguard Worker (csize,) = struct.unpack("<L", magic) 21*5a923131SAndroid Build Coastguard Worker if index + 4 + csize >= len(data) or csize == 0: 22*5a923131SAndroid Build Coastguard Worker break 23*5a923131SAndroid Build Coastguard Worker print("Legacy lz4 block at {}, compressed data size {}".format(index, csize)) 24*5a923131SAndroid Build Coastguard Worker index += csize 25*5a923131SAndroid Build Coastguard Worker 26*5a923131SAndroid Build Coastguard Worker except ValueError: 27*5a923131SAndroid Build Coastguard Worker break 28*5a923131SAndroid Build Coastguard Worker 29*5a923131SAndroid Build Coastguard Worker 30*5a923131SAndroid Build Coastguard Workerdef scan_lz4_frames(data): 31*5a923131SAndroid Build Coastguard Worker index = 0 32*5a923131SAndroid Build Coastguard Worker while index < len(data): 33*5a923131SAndroid Build Coastguard Worker try: 34*5a923131SAndroid Build Coastguard Worker index = data.index(LZ4_FRAME_MAGIC, index) 35*5a923131SAndroid Build Coastguard Worker frame_offset = index 36*5a923131SAndroid Build Coastguard Worker index += 4 37*5a923131SAndroid Build Coastguard Worker flag = data[index] 38*5a923131SAndroid Build Coastguard Worker block_descriptor = data[index+1] 39*5a923131SAndroid Build Coastguard Worker block_checksum_present = flag & 0x10 != 0 40*5a923131SAndroid Build Coastguard Worker content_size_present = flag & 0x8 != 0 41*5a923131SAndroid Build Coastguard Worker content_checksum_present = flag & 0x4 != 0 42*5a923131SAndroid Build Coastguard Worker dictionary_id = flag & 0x1 != 0 43*5a923131SAndroid Build Coastguard Worker index += 2 44*5a923131SAndroid Build Coastguard Worker content_size = None 45*5a923131SAndroid Build Coastguard Worker if content_size_present: 46*5a923131SAndroid Build Coastguard Worker content_size = struct.unpack("<Q", data[index:index+8]) 47*5a923131SAndroid Build Coastguard Worker index += 8 48*5a923131SAndroid Build Coastguard Worker if dictionary_id: 49*5a923131SAndroid Build Coastguard Worker dictionary_id = struct.unpack("<L", data[index:index+4]) 50*5a923131SAndroid Build Coastguard Worker index += 4 51*5a923131SAndroid Build Coastguard Worker header_checksum = data[index:index+1] 52*5a923131SAndroid Build Coastguard Worker index += 1 53*5a923131SAndroid Build Coastguard Worker print("Lz4 frame at {}, content size: {}".format( 54*5a923131SAndroid Build Coastguard Worker frame_offset, content_size)) 55*5a923131SAndroid Build Coastguard Worker while index < len(data): 56*5a923131SAndroid Build Coastguard Worker (block_size,) = struct.unpack("<L", data[index:index+4]) 57*5a923131SAndroid Build Coastguard Worker uncompressed = block_size & 0x80000000 != 0 58*5a923131SAndroid Build Coastguard Worker block_size &= 0x7FFFFFFF 59*5a923131SAndroid Build Coastguard Worker index += 4 60*5a923131SAndroid Build Coastguard Worker index += block_size 61*5a923131SAndroid Build Coastguard Worker if index >= len(data) or block_size == 0: 62*5a923131SAndroid Build Coastguard Worker break 63*5a923131SAndroid Build Coastguard Worker print("Block uncompressed: {}, size: {}".format(uncompressed, block_size)) 64*5a923131SAndroid Build Coastguard Worker except ValueError: 65*5a923131SAndroid Build Coastguard Worker break 66*5a923131SAndroid Build Coastguard Worker 67*5a923131SAndroid Build Coastguard Worker 68*5a923131SAndroid Build Coastguard Workerdef main(argv): 69*5a923131SAndroid Build Coastguard Worker if len(argv) != 2: 70*5a923131SAndroid Build Coastguard Worker print("Usage:", argv[0], "<path to a file>") 71*5a923131SAndroid Build Coastguard Worker return 1 72*5a923131SAndroid Build Coastguard Worker path = argv[1] 73*5a923131SAndroid Build Coastguard Worker 74*5a923131SAndroid Build Coastguard Worker with open(path, "rb") as fp: 75*5a923131SAndroid Build Coastguard Worker data = fp.read() 76*5a923131SAndroid Build Coastguard Worker scan_legacy_lz4_frames(data) 77*5a923131SAndroid Build Coastguard Worker scan_lz4_frames(data) 78*5a923131SAndroid Build Coastguard Worker 79*5a923131SAndroid Build Coastguard Worker 80*5a923131SAndroid Build Coastguard Workerif __name__ == '__main__': 81*5a923131SAndroid Build Coastguard Worker import sys 82*5a923131SAndroid Build Coastguard Worker sys.exit(main(sys.argv)) 83