1a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner#! /usr/bin/env python 2a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 3a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# Copyright (C) 2012 The Android Open Source Project 4a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# 5a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# Licensed under the Apache License, Version 2.0 (the "License"); 6a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# you may not use this file except in compliance with the License. 7a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# You may obtain a copy of the License at 8a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# 9a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# http://www.apache.org/licenses/LICENSE-2.0 10a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# 11a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# Unless required by applicable law or agreed to in writing, software 12a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# distributed under the License is distributed on an "AS IS" BASIS, 13a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# See the License for the specific language governing permissions and 15a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner# limitations under the License. 16a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 17a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerfrom __future__ import print_function 18a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerimport getopt, posixpath, signal, struct, sys 19a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 20a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerdef usage(argv0): 21a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print(""" 22a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' TurnerUsage: %s [-v] sparse_image_file ... 23a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner -v verbose output 24a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner""" % ( argv0 )) 25a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner sys.exit(2) 26a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 27a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerdef main(): 28a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 29a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner signal.signal(signal.SIGPIPE, signal.SIG_DFL) 30a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 31a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner me = posixpath.basename(sys.argv[0]) 32a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 33a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner # Parse the command line 34a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner verbose = 0 # -v 35a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner try: 36a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner opts, args = getopt.getopt(sys.argv[1:], 37a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner "v", 38a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner ["verbose"]) 39a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner except getopt.GetoptError, e: 40a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print(e) 41a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner usage(me) 42a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner for o, a in opts: 43a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if o in ("-v", "--verbose"): 44a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner verbose += 1 45a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner else: 46a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Unrecognized option \"%s\"" % (o)) 47a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner usage(me) 48a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 49a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if len(args) == 0: 50a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("No sparse_image_file specified") 51a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner usage(me) 52a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 53a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner for path in args: 54a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner FH = open(path, 'rb') 55a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner header_bin = FH.read(28) 56a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner header = struct.unpack("<I4H4I", header_bin) 57a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 58a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner magic = header[0] 59a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner major_version = header[1] 60a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner minor_version = header[2] 61a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner file_hdr_sz = header[3] 62a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner chunk_hdr_sz = header[4] 63a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner blk_sz = header[5] 64a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner total_blks = header[6] 65a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner total_chunks = header[7] 66a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner image_checksum = header[8] 67a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 68a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if magic != 0xED26FF3A: 69a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("%s: %s: Magic should be 0xED26FF3A but is 0x%08X" 70a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (me, path, magic)) 71a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner continue 72a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if major_version != 1 or minor_version != 0: 73a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("%s: %s: I only know about version 1.0, but this is version %u.%u" 74a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (me, path, major_version, minor_version)) 75a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner continue 76a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if file_hdr_sz != 28: 77a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("%s: %s: The file header size was expected to be 28, but is %u." 78a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (me, path, file_hdr_sz)) 79a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner continue 80a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if chunk_hdr_sz != 12: 81a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("%s: %s: The chunk header size was expected to be 12, but is %u." 82a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (me, path, chunk_hdr_sz)) 83a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner continue 84a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 85a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("%s: Total of %u %u-byte output blocks in %u input chunks." 86a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (path, total_blks, blk_sz, total_chunks)) 87a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 88a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if image_checksum != 0: 89a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("checksum=0x%08X" % (image_checksum)) 90a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 91a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if not verbose: 92a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner continue 93a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print(" input_bytes output_blocks") 94a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("chunk offset number offset number") 95a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner offset = 0 96a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner for i in xrange(1,total_chunks+1): 97a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner header_bin = FH.read(12) 98a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner header = struct.unpack("<2H2I", header_bin) 99a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner chunk_type = header[0] 100a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner reserved1 = header[1] 101a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner chunk_sz = header[2] 102a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner total_sz = header[3] 103a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner data_sz = total_sz - 12 104a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 105a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("%4u %10u %10u %7u %7u" % (i, FH.tell(), data_sz, offset, chunk_sz), 106a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner end=" ") 107a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 108a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if chunk_type == 0xCAC1: 109a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if data_sz != (chunk_sz * blk_sz): 110a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Raw chunk input size (%u) does not match output size (%u)" 111a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (data_sz, chunk_sz * blk_sz)) 112a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner break; 113a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner else: 114a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Raw data", end="") 115a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner FH.read(data_sz) 116a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner elif chunk_type == 0xCAC2: 117a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if data_sz != 4: 118a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Fill chunk should have 4 bytes of fill, but this has %u" 119a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (data_sz), end="") 120a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner break; 121a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner else: 122a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner fill_bin = FH.read(4) 123a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner fill = struct.unpack("<I", fill_bin) 124a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Fill with 0x%08X" % (fill)) 125a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner elif chunk_type == 0xCAC3: 126a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if data_sz != 0: 127a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Don't care chunk input size is non-zero (%u)" % (data_sz)) 128a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner break; 129a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner else: 130a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Don't care", end="") 131a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner elif chunk_type == 0xCAC4: 132a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if data_sz != 4: 133a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("CRC32 chunk should have 4 bytes of CRC, but this has %u" 134a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (data_sz), end="") 135a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner break; 136a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner else: 137a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner crc_bin = FH.read(4) 138a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner crc = struct.unpack("<I", crc) 139a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Unverified CRC32 0x%08X" % (crc)) 140a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner else: 141a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("Unknown chunk type 0x%04X" % (chunk_type), end="") 142a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner break; 143a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 144a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if verbose > 1: 145a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner header = struct.unpack("<12B", header_bin) 146a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)" 147a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (header[0], header[1], header[2], header[3], 148a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner header[4], header[5], header[6], header[7], 149a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner header[8], header[9], header[10], header[11])) 150a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner else: 151a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print() 152a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 153a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner offset += chunk_sz 154a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 155a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print(" %10u %7u End" % (FH.tell(), offset)) 156a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 157a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if total_blks != offset: 158a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("The header said we should have %u output blocks, but we saw %u" 159a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (total_blks, offset)) 160a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 161a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner junk_len = len(FH.read()) 162a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner if junk_len: 163a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner print("There were %u bytes of extra data at the end of the file." 164a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner % (junk_len)) 165a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 166a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner sys.exit(0) 167a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner 168a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turnerif __name__ == "__main__": 169a2394cf2fab37ca4ec91e57db74f06f15a3656beDavid 'Digit' Turner main() 170