1# NOTE: This script is test under Python 3.x
2
3__copyright__ = "Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved"
4
5import sys
6import crcmod
7
8
9class UnpackImage:
10
11    def __init__(self, pack_file_name, nocrc):
12        self.img_list = []
13        try:
14            with open(pack_file_name, "rb") as pack_file:
15                self.pack_data = pack_file.read()
16        except (IOError, OSError) as err:
17            print(f"Open {pack_file_name} failed")
18            sys.exit(err)
19
20        if self.pack_data[0:4] != b'\x20\x54\x56\x4e':
21            print(f"{pack_file_name} marker check failed")
22            sys.exit(0)
23
24        print("Waiting for unpack Images ...")
25        if nocrc == 0:
26            print("check pack file crc32 ...")
27            crc32_func = crcmod.predefined.mkCrcFun('crc-32')
28            checksum = crc32_func(self.pack_data[8:])
29            if checksum != int.from_bytes(self.pack_data[4:8], byteorder='little'):
30                print(f"{pack_file_name} CRC check failed")
31                sys.exit(0)
32        self.image_cnt = int.from_bytes(self.pack_data[8:12], byteorder='little')
33        # 1st image descriptor begins @ 0x10
34        index = 0x10
35        for _ in range(self.image_cnt):
36            # Put the image length, offset ,attribute in list
37            self.img_list.append([int.from_bytes(self.pack_data[index: index + 8], byteorder='little'),
38                                  int.from_bytes(self.pack_data[index + 8: index + 16], byteorder='little'),
39                                  int.from_bytes(self.pack_data[index + 16: index + 20], byteorder='little'),
40                                  index + 24])
41            index += int.from_bytes(self.pack_data[index: index + 8], byteorder='little') + 24  # 24 is image header
42            if index % 16 != 0:
43                index += 16 - (index & 0xF)   # round to 16-byte align
44
45    def img_count(self):
46        return self.image_cnt
47
48    def img_attr(self, index):
49        if index < self.image_cnt:
50            # No need to return the last entry, actual offset in image file.
51            # And should return integers instead of list of integer here
52            return self.img_list[index][0], self.img_list[index][1], self.img_list[index][2]
53        else:
54            print("Invalid image index")
55            return 0, 0, 0
56
57    def img_content(self, index, offset, size):
58        if index >= self.image_cnt:
59            print("Invalid image index")
60            return ''
61        if offset > self.img_list[index][0] or offset + size > self.img_list[index][0]:
62            print("Invalid offset")
63            return ''
64
65        return self.pack_data[self.img_list[index][3] + offset: self.img_list[index][3] + offset + size]
66