Skip to content

Instantly share code, notes, and snippets.

@hcs64
Created February 1, 2023 21:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hcs64/84b530e2becc5b0420f54e9767c39b6a to your computer and use it in GitHub Desktop.
Save hcs64/84b530e2becc5b0420f54e9767c39b6a to your computer and use it in GitHub Desktop.
Decode strings from some feelplus games
# Translate feelplus packed strings
# Derived from examples at https://pastebin.com/UkfBaSga
import itertools
import struct
# Unknown char 39 is shown as "{39}"
charset1 = ['{%s}'%(i,) for i in range(40)]
for i in range(10):
charset1[i + 1] = str(i)
for i, c in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
charset1[11 + i] = c
charset1[37] = '_'
charset1[38] = '.'
def unpack(words, char_count):
for v in words:
x = v % char_count
v = (v - x) // char_count
if x == 0:
return
yield x
y = v % char_count
v = (v - y) // char_count
if y == 0:
return
yield y
z = v
if z == 0:
return
yield z
def wswap(dw):
return struct.unpack("<H", struct.pack(">H", dw))[0]
# decode
#
# skip_middle_repeat: Otherwise 9274e791 be96efee be96efee cd4a0000 decodes to
# BGM01_TITLE.TITLE.XWV
def decode(hex_code, charset = charset1, skip_middle_repeat = True, big_endian = True):
# parse string as hex
dwords = list(map(lambda x: int(x, base=16), hex_code.split()))
# drop repeated middle dword
if skip_middle_repeat and len(dwords) == 4 and dwords[1] == dwords[2]:
dwords = dwords[0:2] + dwords[3:]
# split into 16-bit words
words = itertools.chain.from_iterable([dword >> 16, dword & 0xffff] for dword in dwords)
# swap each word if little endian
if not big_endian:
words = [wswap(w) for w in words]
# make string
return ''.join(charset[c] for c in unpack(words, len(charset)))
# Moon Diver
print(decode("9274e791 be96efee be96efee cd4a0000"))
# Mind Jack
print(decode("b309b16d c02d4734 c02d4734 da870275"))
print(decode("be856373 31a0ebc9 31a0ebc9 8b4f69d7"))
print(decode("be856373 31a0ebc9 31a0ebc9 8b4f69d7", skip_middle_repeat = False))
# Lost Odyssey Demo
print(decode("62e96906 937cc8ef 937cc8ef 6a620000", big_endian = False))
print(decode("d5bab46c b6ba0f00 b6ba0f00 00000000", big_endian = False))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment