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/Utils.py
PkgToolBox / Utilities / Trophy / Utils.py
1import struct
2import io
3import zipfile
4from typing import List, Optional
5 
6class Utils:
7 @staticmethod
8 def hex_to_binary(hex_string: str) -> bytes:
9 return bytes.fromhex(hex_string)
10 
11 @staticmethod
12 def hex_to_dec(hex_bytes: bytes, reverse: str = "") -> int:
13 if reverse == "reverse":
14 hex_bytes = hex_bytes[::-1]
15 return int.from_bytes(hex_bytes, byteorder='little')
16 
17 @staticmethod
18 def read_write_data(file_to_use: str, file_to_use2: str = "", method_read_or_write_or_both: str = "",
19 method_binary_or_integer: str = "", bin_data: Optional[bytes] = None,
20 bin_data2: int = 0, offset: int = 0, count: int = 0):
21 if method_read_or_write_or_both == "r":
22 with open(file_to_use, "rb") as f:
23 return f.read()
24 elif method_read_or_write_or_both == "w":
25 with open(file_to_use, "ab") as f:
26 if method_binary_or_integer == "bi":
27 f.write(bin_data)
28 elif method_binary_or_integer == "in":
29 f.write(bin_data2.to_bytes(4, byteorder='little'))
30 elif method_read_or_write_or_both == "b":
31 with open(file_to_use, "rb") as fr, open(file_to_use2, "ab") as fw:
32 working_buffer_size = min(4096, count) if count > 0 else 4096
33 fr.seek(offset)
34 while True:
35 buffer = fr.read(working_buffer_size)
36 if not buffer:
37 break
38 fw.write(buffer)
39 if count > 0:
40 count -= len(buffer)
41 if count <= 0:
42 break
43 working_buffer_size = min(working_buffer_size, count)
44 
45 @staticmethod
46 def compare_bytes(a: bytes, b: bytes) -> bool:
47 return a == b
48 
49 @staticmethod
50 def extract_file_to_directory(zip_file_name: str, output_directory: str):
51 with zipfile.ZipFile(zip_file_name, 'r') as zip_ref:
52 zip_ref.extract("TheFileToExtract", output_directory)
53 
54 @staticmethod
55 def byte_to_string(buff: bytes) -> str:
56 return buff.hex().upper()
57 
58 @staticmethod
59 def generate_stream_from_string(s: str) -> io.BytesIO:
60 return io.BytesIO(s.encode())
61 
62 @staticmethod
63 def read_uint32(stream: io.BytesIO) -> int:
64 return struct.unpack('<I', stream.read(4))[0]
65 
66 @staticmethod
67 def read_uint16(stream: io.BytesIO) -> int:
68 return struct.unpack('<H', stream.read(2))[0]
69 
70 @staticmethod
71 def read_ascii_string(stream: io.BytesIO, length: int) -> str:
72 return stream.read(length).decode('ascii')
73 
74 @staticmethod
75 def read_utf8_string(stream: io.BytesIO, length: int) -> str:
76 return stream.read(length).decode('utf-8')
77 
78 @staticmethod
79 def read_byte(stream: io.BytesIO, length: int) -> bytes:
80 return stream.read(length)
81 
82 @staticmethod
83 def bytes_to_bitmap(img_bytes: bytes):
84 # This would require a Python imaging library like Pillow
85 from PIL import Image
86 import io
87 return Image.open(io.BytesIO(img_bytes))
88 
89 @staticmethod
90 def is_linux() -> bool:
91 import platform
92 return platform.system() == "Linux"
93 
94 @staticmethod
95 def contain(a: bytes, b: bytes) -> bool:
96 return a == b
97 
98 @staticmethod
99 def hex_to_string(hex_string: str) -> str:
100 return bytes.fromhex(hex_string).decode('ascii')
101 
102 @staticmethod
103 def hex(byte: int) -> str:
104 return f"{byte:02X}"
105 
106 @staticmethod
107 def byte_array_to_little_endian_integer(bits: bytes) -> int:
108 return int.from_bytes(bits, byteorder='little')
109 
110 @staticmethod
111 def byte_arrays_equal(first: bytes, second: bytes) -> bool:
112 return first == second
113 
114 @staticmethod
115 def byte_array_to_utf8_string(byte_array: bytes) -> str:
116 return byte_array.decode('utf-8')
117 
118 @staticmethod
119 def byte_array_to_hex_string(bytes_input: bytes) -> str:
120 return bytes_input.hex().upper()
121 
122 @staticmethod
123 def hex_string_to_long(str_hex: str) -> int:
124 return int(str_hex, 16)
125 
126 @staticmethod
127 def create_jagged_array(lengths: List[int]):
128 def create_inner(index: int):
129 if index == len(lengths) - 1:
130 return [None] * lengths[index]
131 return [create_inner(index + 1) for _ in range(lengths[index])]
132 return create_inner(0)
133 
134 @staticmethod
135 def clamp(value: int, min_value: int, max_value: int) -> int:
136 return max(min(value, max_value), min_value)
137 
138 @staticmethod
139 def clamp16(value: int) -> int:
140 return Utils.clamp(value, -32768, 32767)
141 
142 @staticmethod
143 def clamp4(value: int) -> int:
144 return Utils.clamp(value, -8, 7)
145 
146 
147