mirror of
https://github.com/CosmicScale/PSBBN-Definitive-English-Patch.git
synced 2025-07-22 21:37:25 +02:00

- Bypass boot ELF security check; custom kernels now supported - Swap X/O buttons (X=Enter, O=Back) - Add DVD remote support in Music and Movie channels - Update BB Guide: reflect button swap, game collection changes, and more - Improve update process: no USB keyboard required after this version - Allow custom POPS partition size in installer - Add support for multi-disc PS1 games with auto-generated DISCS.TXT and shared VMCs - Add VMC Groups (shared saves for compatible PS1 games) - Improve VMC display: custom icons and clearer titles in Browser 2.0 - Generate HDD-OSD icons automatically using OPL art or game logos - Contribute new icons to HDD-OSD icon database and report missing ones - Improve Game ID detection in list-builder.py for non-standard PS1/PS2 titles - Update Neutrino to v1.7.0 - Update OPL to v1.2.0 Beta-2210-6b300b0 (adds VMC Group support) - Upgrade wLaunchELF to v4.43x_isr (adds exFAT + MMCE support)
103 lines
2.8 KiB
Python
103 lines
2.8 KiB
Python
import sys
|
||
import os
|
||
import unicodedata
|
||
|
||
# Mapping for unsupported or problematic characters
|
||
REPLACEMENTS = {
|
||
"'": "’",
|
||
"-": "ー",
|
||
# Subscript numbers
|
||
"₀": "0",
|
||
"₁": "1",
|
||
"₂": "2",
|
||
"₃": "3",
|
||
"₄": "4",
|
||
"₅": "5",
|
||
"₆": "6",
|
||
"₇": "7",
|
||
"₈": "8",
|
||
"₉": "9",
|
||
}
|
||
|
||
def ascii_to_fullwidth(text):
|
||
result = []
|
||
for c in text:
|
||
# Replace mapped characters
|
||
if c in REPLACEMENTS:
|
||
c = REPLACEMENTS[c]
|
||
# Decompose accented characters to base (e.g., é → e)
|
||
c = unicodedata.normalize('NFD', c)[0]
|
||
|
||
code = ord(c)
|
||
if 0x21 <= code <= 0x7E:
|
||
fullwidth_char = chr(code + 0xFEE0)
|
||
elif c == ' ':
|
||
fullwidth_char = '\u3000'
|
||
else:
|
||
fullwidth_char = c
|
||
result.append(fullwidth_char)
|
||
return ''.join(result)
|
||
|
||
def sanitize_for_shift_jis(text):
|
||
return ''.join(c for c in text if can_encode_shift_jis(c))
|
||
|
||
def can_encode_shift_jis(char):
|
||
try:
|
||
char.encode("shift_jis")
|
||
return True
|
||
except UnicodeEncodeError:
|
||
return False
|
||
|
||
def update_icon_sys(path, title0, title1):
|
||
if len(title0) > 16 or len(title1) > 16:
|
||
print("[!] Error: Both title0 and title1 must be 16 characters or fewer.")
|
||
sys.exit(1)
|
||
|
||
try:
|
||
with open(path, "rb") as f:
|
||
data = bytearray(f.read())
|
||
|
||
title_block_offset = 0xC0
|
||
title_block_length = 68
|
||
|
||
# Convert to full-width, replace unsupported, and sanitize
|
||
title0_fw = sanitize_for_shift_jis(ascii_to_fullwidth(title0))
|
||
title1_fw = sanitize_for_shift_jis(ascii_to_fullwidth(title1))
|
||
|
||
title0_encoded = title0_fw.encode("shift_jis")
|
||
title1_encoded = title1_fw.encode("shift_jis")
|
||
|
||
split_offset = len(title0_encoded)
|
||
if split_offset > 68:
|
||
print("[!] Error: title0 too long after encoding.")
|
||
sys.exit(1)
|
||
|
||
title_combined = title0_encoded + title1_encoded
|
||
title_block = title_combined[:title_block_length].ljust(title_block_length, b'\x00')
|
||
|
||
# Set split offset at byte 0x06
|
||
data[0x06] = split_offset
|
||
|
||
data[title_block_offset:title_block_offset + title_block_length] = title_block
|
||
|
||
with open("icon.sys", "wb") as f:
|
||
f.write(data)
|
||
|
||
# print(f"[✓] Updated icon.sys with dynamic split offset ({split_offset:#04x}): {path}")
|
||
|
||
except Exception as e:
|
||
print(f"[!] Failed to update icon.sys: {e}")
|
||
sys.exit(1)
|
||
|
||
if __name__ == "__main__":
|
||
if len(sys.argv) != 4:
|
||
print("Usage: python3 txt_to_icon_sys.py path/to/icon.sys title0 title1")
|
||
sys.exit(1)
|
||
|
||
_, icon_path, title0, title1 = sys.argv
|
||
if not os.path.isfile(icon_path):
|
||
print(f"[!] File not found: {icon_path}")
|
||
sys.exit(1)
|
||
|
||
update_icon_sys(icon_path, title0, title1)
|