Skip to content

Commit

Permalink
Should now work properly
Browse files Browse the repository at this point in the history
  • Loading branch information
TuxSH committed Oct 26, 2015
1 parent c27c6e1 commit ede3ae3
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 15 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,7 @@ target/

# Visual Studio
*.pyproj
*.sln
*.sln

# Custom
1_M3_houseD_1F.txt
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# XDscriptTools
XD script tools (disassembler, etc...)
Requires Python 3
14 changes: 11 additions & 3 deletions XDscriptDisassembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,22 @@

from XDscriptLib import *
import argparse
import sys
import os


if __name__ == '__main__':
if sys.version_info[0] < 3:
raise RuntimeError("Python 3 required")

parser = argparse.ArgumentParser()
parser.add_argument("files", help="XD script files to disassemble", nargs='+', type=str)
args = parser.parse_args()
fnames = args.files

for fname in args.files:
for fname in fnames:
with open(fname, "rb") as f:
out_fname = fname.split('.')[0]+".txt"
out_fname = os.path.splitext(fname)[0]+'.txt'
contents = f.read()
with open(out_fname, "w") as out_f:
out_f.write(str(ScriptCtx(f.read())))
out_f.write(str(ScriptCtx(contents)))
24 changes: 20 additions & 4 deletions XDscriptLib/_Instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Instruction(object):
Instruction -- represents a XD script instruction
For the PAL version, the script interpreter is at 8023D83C
ctx: ScriptCtx (attribute)
label: string
position: int, nextPosition
Expand All @@ -19,7 +20,7 @@ class Instruction(object):
parameter: 16-bit signed integer, not always used
**Opcodes**:
See below. int, float, str, and vector are the only 'copyable' types, ldcpvar is used for them.
See below. int, float, str, and vector are the only 'copyable' types, ldvar is used for them.
For all other existing types, ldncpvar is used (if ldncpvar is followed by setvar, the source variable is deleted)
Expand All @@ -29,6 +30,17 @@ class Instruction(object):
**Types**:
Refer to ScriptVar
**Stack**:
It is limited to 256 elements. Each task has its own stack. See FunctionInfo for further details.
**Tasks**:
The XD script engine is based on multitasking. 8 tasks max., either synchronous (blocking, and in the same thread),
or asynchronous (in a different thread). NB: GS uses its own threading system.
Task signature: either:
4 ints,
or a character (for character interaction handlers)
Properties:
- subSubOpcodes:
Expand All @@ -54,7 +66,7 @@ class Instruction(object):
"""

instructionNames = ("nop", "operator", "ldimm",
"ldcpvar", "setvar", "setvector",
"ldvar", "setvar", "setvector",
"pop", "call", "return",
"callstd", "jmptrue", "jmpfalse",
"jmp", "reserve", "release",
Expand Down Expand Up @@ -198,7 +210,7 @@ def check(self):


elif self._opcode in (3, 4, 17):
# ldcpvar, setvar, ldncpvar
# ldvar, setvar, ldncpvar
self.checkVariable()
if self.subSubOpcodes[1] == 3 and self._opcode == 4:
warnings.warn("cannot change immutable reference (instruction #{0})".format(hex(self.position)))
Expand All @@ -223,6 +235,10 @@ def check(self):
self.name, hex(instrID)))

else:
if self._opcode == 7 and instrID not in self.ctx.sections["HEAD"].functionOffsets:
warnings.warn("call to unreferenced function ({0} \
at instruction #{1})".format(instrID, hex(self.position)))

lbl = ''.join(["sub_" if self._opcode == 7 else "loc_", hex(instrID)[2:]])
if not self.ctx.sections["CODE"].labels[instrID]: self.ctx.sections["CODE"].labels[instrID] = lbl
if self._opcode != 7 and (True if self.ctx is None
Expand Down Expand Up @@ -366,7 +382,7 @@ def __str__(self):
else:
instrstr = "{0}, {1}".format(self._subOpcode, self._parameter & 0xffff)

elif self._opcode in (3, 4, 17): # ldcpvar, setvar, ldncpvar
elif self._opcode in (3, 4, 17): # ldvar, setvar, ldncpvar
instrstr = self.variableName

elif self._opcode == 5: # setvector
Expand Down
25 changes: 19 additions & 6 deletions XDscriptLib/_ScriptCtx.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def parseFTBLSection(self):
for i in range(sec.nbElems):
code_off = struct.unpack_from(">I", sec.data, 8*i)[0]
nm_off = struct.unpack_from(">I", sec.data, 4 + 8*i)[0] - 0x20
if 0 > nm_off or nm_off + 0x20 >= len(sec.data): continue
if 0 > nm_off or nm_off >= len(sec.data):
continue
nm = sec.data[nm_off:sec.data.find(b'\x00', nm_off)].decode('sjis')
sec.functionTable.append((code_off, nm))

Expand Down Expand Up @@ -114,6 +115,9 @@ def parseARRYSection(self):
def load(self, src):
if src[:4] != b'TCOD': warnings.warn("Apparently not a XD script file!")
self.totalSize = struct.unpack_from(">I", src, 4)[0]
if self.totalSize != len(src):
warnings.warn("len(src) is different from the script stored total size")

self.loadSections(src)
self.parseFTBLSection()
self.parseHEADSection()
Expand All @@ -126,11 +130,18 @@ def load(self, src):

ftbl = self.sections.get("FTBL")
code = self.sections["CODE"]
head = self.sections["HEAD"]


if ftbl is not None:
if not ftbl.nbElems == head.nbElems == code.nbElems:
warnings.warn("Inconsistent number of functions between FTBL, HEAD, and CODE")
for (off, nm) in ftbl.functionTable:
code.labels[off] = nm
elif head.nbElems != code.nbElems:
warnings.warn("Inconsistent number of functions between HEAD, and CODE")

entryPoint = self.sections["HEAD"].valueOffset
entryPoint = head.valueOffset
if not code.labels[entryPoint]: code.labels[entryPoint] = "__start"

def __init__(self, src): self.load(src)
Expand All @@ -156,7 +167,9 @@ def __str__(self):

out.write('.section "HEAD":\n')
out.write('\t.set __ENTRY_POINT__, {0}\n'.format(code.labels[head.valueOffset]))
for off in head.functionOffsets: out.write('\t.function {0}\n'.format(code.labels[off]))
for off in head.functionOffsets:
if not code.labels[off]: code.labels[off] = 'sub_{0}'.format(hex(off))
out.write('\t.function {0}\n'.format(code.labels[off]))
out.write('\n')

out.write('.section "CODE":\n')
Expand All @@ -166,11 +179,11 @@ def __str__(self):
separator_printed = False
if (ftbl is not None and code.labels[instr.position] in [nm for (off, nm) in ftbl.functionTable])\
or code.labels[instr.position][:4] == 'sub_':
out.write('\n\n;=================SUBROUTINE===================\n')
out.write('\n\n;=============================SUBROUTINE==============================\n')
separator_printed = True

elif code.labels[instr.position][:4] == 'loc_':
out.write(';----------------------------------------------\n')
out.write(';---------------------------------------------------------------------\n')
separator_printed = True

if code.labels[instr.position]:
Expand All @@ -186,7 +199,7 @@ def __str__(self):

if strg is not None:
out.write('.section "STRG":\n')
splt = strg.stringContents.split('\x00')
splt = strg.stringContents.rstrip('\x00').split('\x00')
if splt != ['']:
for s in splt:
out.write('\t"{0}",\n'.format(s))
Expand Down
2 changes: 1 addition & 1 deletion XDscriptLib/_ScriptVar.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ScriptVar(object):
"""Script variable:
struct XDscriptVar {
s16 type; // 0x00 -- 0x01, s16
// 0x02--0x03: padding
0x02--0x03: unknown (unsused by the interpreter)
union{
s32 asInt;
float asFloat;
Expand Down
Binary file added common_script.scd
Binary file not shown.

0 comments on commit ede3ae3

Please sign in to comment.