Seregon/PkgToolBox

Toolbox for analyzing and editing pkg application files for psp,ps3, ps4 and ps5, includes the most useful functions you might need.

Python/57.3 KB/No license
Utilities/Trophy/Trophy.py
PkgToolBox / Utilities / Trophy / Trophy.py
1import hashlib
2import struct
3
4class TrophyFile:
5 def __init__(self, file_path=None):
6 self.SHA1 = ""
7 self.Bytes = None
8 self.Readbytes = False
9 self.trophyItemList = []
10 self._iserror = False
11 self._error = ""
12 self._inputfile = ""
13 self._calculatedsha1 = ""
14 self.trphy = self.TrophyHeader()
15
16 if file_path:
17 self.load(file_path)
18
19 class TrophyHeader:
20 def __init__(self):
21 self.magic = bytearray(4)
22 self.version = bytearray(4)
23 self.file_size = bytearray(8)
24 self.files_count = bytearray(4)
25 self.element_size = bytearray(4)
26 self.dev_flag = bytearray(4)
27 self.sha1 = bytearray(20)
28 self.padding = bytearray(36)
29
30 class TrophyItem:
31 def __init__(self, index, name, offset, size, total_bytes):
32 self.Index = index
33 self.Name = name
34 self.Offset = offset
35 self.Size = size
36 self.TotalBytes = total_bytes
37
38 @property
39 def file_count(self):
40 return struct.unpack('<I', self.trphy.files_count)[0]
41
42 @property
43 def version(self):
44 return struct.unpack('<I', self.trphy.version)[0]
45
46 def load_header(self, fs):
47 hdr = self.TrophyHeader()
48 hdr.magic = fs.read(4)
49 hdr.version = fs.read(4)
50 hdr.file_size = fs.read(8)
51 hdr.files_count = fs.read(4)
52 hdr.element_size = fs.read(4)
53 hdr.dev_flag = fs.read(4)
54 version = struct.unpack('<I', hdr.version)[0]
55 if 1 <= version <= 3:
56 if version == 1:
57 hdr.padding = fs.read(36)
58 elif version == 2:
59 hdr.sha1 = fs.read(20)
60 hdr.padding = fs.read(16)
61 elif version == 3:
62 hdr.sha1 = fs.read(20)
63 hdr.padding = fs.read(48)
64 return hdr
65
66 def read_content(self, fs):
67 for i in range(self.file_count):
68 array = fs.read(36)
69 array2 = fs.read(4)
70 array3 = fs.read(8)
71 array4 = fs.read(4)
72 fs.seek(12, 1)
73 name = array.decode('utf-8').replace('\0', '')
74 offset = int.from_bytes(array2, 'little')
75 size = int.from_bytes(array3, 'little')
76 if self.Readbytes:
77 with memoryview(self.Bytes) as mv:
78 total_bytes = mv[offset:offset + size].tobytes()
79 self.trophyItemList.append(self.TrophyItem(i, name, offset, size, total_bytes))
80 else:
81 self.trophyItemList.append(self.TrophyItem(i, name, offset, size, None))
82
83 def calculate_sha1_hash(self):
84 if self.version > 1:
85 sha1 = hashlib.sha1()
86 with memoryview(self.Bytes) as mv:
87 sha1.update(mv[:28])
88 sha1.update(b'\x00' * 20)
89 sha1.update(mv[48:])
90 return sha1.hexdigest().upper()
91 return None
92
93 def load(self, file_path):
94 self.SHA1 = ""
95 self.trophyItemList = []
96 with open(file_path, 'rb') as file_stream:
97 self.Bytes = file_stream.read()
98 file_stream.seek(0)
99 self.trphy = self.load_header(file_stream)
100 if self.trphy.magic != b'\xdc\xa2\x4d\x00':
101 raise Exception("This file is not supported!")
102 self.read_content(file_stream)
103 if self.version > 1:
104 self.SHA1 = self.calculate_sha1_hash()
105
106 def extract_file_to_memory(self, filename):
107 for item in self.trophyItemList:
108 if item.Name == filename:
109 with memoryview(self.Bytes) as mv:
110 return mv[item.Offset:item.Offset + item.Size].tobytes()
111 return None
112