Skip to content

Instantly share code, notes, and snippets.

@jaames
Last active April 27, 2023 20:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaames/daaf2531bae31f72cca675df4361c0d4 to your computer and use it in GitHub Desktop.
Save jaames/daaf2531bae31f72cca675df4361c0d4 to your computer and use it in GitHub Desktop.
convert Flipnote Studio .lst and .pls files to and from .txt
from sys import argv
import hashlib
import numpy as np
xorkey = [
0xF7, 0x4C, 0x6A, 0x3A, 0xFB, 0x82, 0xA6, 0x37,
0x6E, 0x11, 0x38, 0xCF, 0xA0, 0xDD, 0x85, 0xC0,
0xC7, 0x9B, 0xC4, 0xD8, 0xDD, 0x28, 0x8A, 0x87,
0x53, 0x20, 0xEE, 0xE0, 0x0B, 0xEB, 0x43, 0xA0,
0xDB, 0x55, 0x0F, 0x75, 0x36, 0x37, 0xEB, 0x35,
0x6A, 0x34, 0x7F, 0xB5, 0x0F, 0x99, 0xF7, 0xEF,
0x43, 0x25, 0xCE, 0xA0, 0x29, 0x46, 0xD9, 0xD4,
0x4D, 0xBB, 0x04, 0x66, 0x68, 0x08, 0xF1, 0xF8
]
def xor(data):
# Storage for the decrypted entry data
decrypted = bytes();
# XOR the entry data
for index, byte in enumerate(data):
decrypted += bytes([ byte ^ xorkey[index % len(xorkey)] ]);
# Convert the XOR'ed data to a bytes object
return decrypted
def checksum(data):
hash = hashlib.md5()
hash.update(data)
digest = hash.digest()
return bytes([digest[6], digest[8]])
def decode(lstBuffer, outBuffer):
data = lstBuffer.read()
xordata = xor(data)
# Find the first null byte in the decoded file -- this is where the entry content ends
entryLength = xordata.index(b"\x00") + 1
# Write the entry data to the out buffer, removing the final newline and the null byte at the end
outBuffer.write(xordata.split(b"\x0A\x00")[0])
def encode(txtBuffer, outBuffer, targetLength):
# Split the xtx file buffer into lines
content = txtBuffer.readlines()
# Strip any newlines that are left
content = [x.strip("\n") for x in content]
# Join all the items in content together with newlines between
# (We do all this just to make sure the input is "clean")
content = "\n".join(content)
# Create a bytearray and add the content to it
data = bytearray()
data.extend(map(ord, content))
# Add the trailing newline and null byte
data += bytes([0x0A, 0x00])
# Checksum everything
md5 = checksum(data)
# XOR all the data so far
data = xor(data)
# Add a checksum to the XOR data
data += md5
# Load the data into a numpy array
data = np.fromstring(data, dtype=np.uint8)
# Add null padding
data = np.pad(data, (0, targetLength - len(data)), 'constant', constant_values=(0, 0))
# Convert the array to bytes and write them to the out buffer
outBuffer.write(data.tobytes())
if len(argv) < 3:
print("\nlst.py")
print("writen by james daniel (github.com/jaames)")
print("\nconvert .txt to .lst/.pls:")
print("\tpython3 lst.py -e input.txt output.lst desired_length_in_bytes")
print("\n\tlength reference:")
print("\t.dirmemo2.lst - 160000")
print("\t.mark0.pls | mark1.pls | mark2.pls | mark3.pls - 8000")
print("\t.recent10.pls - 4000")
print("\nconvert .lst/.pls to .txt:")
print("\tpython3 lst.py -d input.lst output.txt")
else:
if argv[1] == "-e":
with open(argv[2], "r") as txt, open(argv[3], "wb") as lst:
encode(txt, lst, int(argv[4]))
elif args[1] == "-d":
with open(argv[2], "rb") as lst, open(argv[3], "wb") as txt:
decode(lst, txt)
@zperk13
Copy link

zperk13 commented Apr 27, 2023

I think you have a typo on line 81, "args" instead of "argv"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment