74 lines
1.8 KiB
Python
74 lines
1.8 KiB
Python
import struct
|
|
from io import BytesIO
|
|
import json
|
|
from os.path import splitext
|
|
|
|
|
|
def read_u32(f):
|
|
return struct.unpack('<I', f.read(4))[0]
|
|
|
|
|
|
def read_cstring(f):
|
|
chars = []
|
|
while True:
|
|
c = f.read(1)
|
|
if c == b'\x00' or c == b'':
|
|
break
|
|
chars.append(c)
|
|
return b''.join(chars)
|
|
|
|
|
|
def rotate_left(val, rshift):
|
|
return ((val << rshift) & 0xFF) | (val >> (8 - rshift))
|
|
|
|
|
|
def decrypt(data: bytes) -> BytesIO:
|
|
pos = 0x10
|
|
shift = 4
|
|
decrypted = bytearray(data)
|
|
while pos + 4 <= len(decrypted):
|
|
data = decrypted[pos:pos+4]
|
|
data[0] = rotate_left(data[0], shift)
|
|
shift = (shift + 1) % 8
|
|
data = struct.unpack('<I', data)[0]
|
|
data ^= 0x084DF873 ^ 0xFF987DEE
|
|
decrypted[pos:pos+4] = struct.pack('<I', data)
|
|
pos += 4
|
|
return BytesIO(decrypted)
|
|
|
|
|
|
def load_text_data(f, e):
|
|
f.read(12) # Skip header
|
|
count = read_u32(f)
|
|
first_idx = read_u32(f)
|
|
if first_idx != 0:
|
|
f.seek(0)
|
|
f = decrypt(f.read())
|
|
f.read(16)
|
|
first_idx = read_u32(f)
|
|
f.seek(16)
|
|
table = {}
|
|
for j in range(count):
|
|
cur = read_u32(f)
|
|
s = read_cstring(f).decode(e)
|
|
table[cur] = s
|
|
return table
|
|
|
|
|
|
if __name__ == '__main__':
|
|
import sys
|
|
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python unpack_softpal_text_dat.py <file> [<output>] [<encoding>]")
|
|
sys.exit(1)
|
|
|
|
filename = sys.argv[1]
|
|
output = sys.argv[2] if len(sys.argv) > 2 else splitext(filename)[0] + '.json'
|
|
encoding = sys.argv[3] if len(sys.argv) > 3 else 'cp932'
|
|
|
|
with open(filename, 'rb') as f:
|
|
table = load_text_data(f, encoding)
|
|
with open(output, 'w', encoding='utf-8') as f:
|
|
json.dump(table, f, ensure_ascii=False, indent=4)
|
|
|