xref: /aosp_15_r20/system/update_engine/scripts/scan_lz4.py (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
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