This decrypts and decompresses the sl2 files:
1 import os, sys, zlib
2 from rijndael import Rijndael
3 from struct import unpack
4
5 for fname in sys.argv[1:]:
6 key = [0x04, 0x38, 0x04, 0x31, 0x2D, 0x32, 0x0C, 0x30, 0x43, 0x2E, 0x08, 0x04, 0x16, 0x30, 0x22, 0x0C]
7 iv = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
8 with open(fname, "rb") as f:
9 with open(fname.replace(".sl2", "")+".txt", "wb") as f2:
10 print(f"handling {fname}")
11 rjn = Rijndael(key, block_size = 16)
12 fdata = f.read()
13
14 plaintext_len = unpack(">I", fdata[0x4C:0x50])[0]
15 ciphertext_len = (plaintext_len//16) * 16
16 if ciphertext_len < plaintext_len:
17 ciphertext_len += 16
18
19 data = fdata[0x50:ciphertext_len+0x50]
20
21 decrypted = []
22 while len(data) >= 16:
23 ciphertext = data[:16]
24 plaintext = rjn.decrypt(ciphertext)
25 for i in range(len(plaintext)):
26 plaintext[i] ^= iv[i]
27 decrypted += plaintext
28 iv = ciphertext
29 data = data[16:]
30 decrypted = decrypted[:plaintext_len]
31
32 if True:
33 decompressed = zlib.decompress(bytes(decrypted))
34
35 string_len = unpack(">I", bytes(decompressed[0x2C:0x30]))[0]
36 text = decompressed[0x30:0x30+string_len-1]
37
38 f2.write(text)
39 else:
40 f2.write(bytes(decrypted))
This parses them:
1 import os, sys, json, re
2
3 for fname in sys.argv[1:]:
4 with open(fname, "r", encoding="cp932") as f:
5 lines = []
6
7 parsing_if = -1
8 data = json.load(f)
9 i = 0
10 while len(data[i:]) > 0:
11 entry = data[i]
12 if parsing_if == 1:
13 if entry != "true":
14 print(entry)
15 print("^-- expected \"true\" block of if statement")
16 exit()
17 else:
18 parsing_if = 2
19 i += 1
20 continue
21 if parsing_if == 2:
22 if entry == "false":
23 parsing_if = 3
24 i += 1
25 continue
26 if parsing_if == 3:
27 if entry == "endif":
28 parsing_if = -1
29 i += 1
30 continue
31 if isinstance(entry, str):
32 if entry == "_if":
33 if parsing_if != -1:
34 print("error: nested if statements not supported")
35 parsing_if = 1
36 i += 2
37 continue
38
39 if entry[0] in "_":
40 # wild guess lol
41 if len(data[i:]) > 1 and not isinstance(data[i+1], str):
42 i += 2
43 else:
44 i += 1
45 continue
46 if entry[0] in "#":
47 i += 1
48 continue
49 if entry in ["ending"]:
50 i += 1
51 continue
52 if entry in ["false", "true", "endif"]:
53 print("in: "+fname)
54 print(parsing_if)
55 print("")
56 print(data[i-6])
57 print(data[i-5])
58 print(data[i-4])
59 print(data[i-3])
60 print(data[i-2])
61 print(data[i-1])
62 print(data[i] + " <---!!")
63 print(data[i+1])
64 print(data[i+2])
65 print(data[i+3])
66 print(data[i+4])
67 print(data[i+5])
68 print(data[i+6])
69 exit()
70 if entry[0] in "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_#":
71 print(data[i-6])
72 print(data[i-5])
73 print(data[i-4])
74 print(data[i-3])
75 print(data[i-2])
76 print(data[i-1])
77 print(data[i] + " <---()")
78 print(data[i+1])
79 print(data[i+2])
80 print(data[i+3])
81 print(data[i+4])
82 print(data[i+5])
83 print(data[i+6])
84 exit()
85 lines += [entry]
86 i += 1
87 else:
88 print(entry)
89 print("^-- unexpected list")
90 exit()
91
92 lastline = ""
93 for line in lines:
94 if line[0] != '/':
95 if lastline.endswith("」"):
96 lastline = re.sub(r"[^「]*(「.*」)", r"\1", lastline)
97 print(lastline)
98 lastline = line
99 else:
100 lastline += line[1:]
101 #if line.endswith("」"):
102 # line =
rijndael.py is here: https://gist.github.com/wareya/e00c80c9d346312354d45516978e3376