Guest User

Nayuta Script Insert v1.3

a guest
Mar 11th, 2015
510
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # v1.3 Inserts 0xC1 opcodes
  2. # v1.2 Specify insert files. Fix more jumps. Does all files in list.
  3. # Insert Nayuta no Kiseki script file / update data.lst
  4. # Usage is python script.py mp_0000
  5. # Where mp_0000.bin is the file you want to insert
  6. # Input file is from the dumper (*.data) with whichever strings you
  7. #   want to insert, in tab-separated format.
  8. # Also need *.orig (original data file) in same directory.
  9. # Also need data.lst from the ROM in same directory.
  10. import os
  11. import struct
  12. import sys
  13. import pdb
  14.  
  15. filelist = ['mp_0000', 'mp_0000c', 'mp_0000d',
  16.             'mp_0001', 'mp_0001c', 'mp_0001d',
  17.             'mp_0002', 'mp_0002c', 'mp_0002d',
  18.             'mp_0003', 'mp_0003c', 'mp_0003d',
  19.             'mp_0004', 'mp_0004c', 'mp_0004d', 'mp_0004n',
  20.             'mp_0005', 'mp_0005c',
  21.             'mp_0100', 'mp_0100a', 'mp_0100b',
  22.             'mp_0101', 'mp_0101a', 'mp_0101b', 'mp_0101c',
  23.             'mp_0102', 'mp_0104', 'mp_0105', 'mp_0106',
  24.             'mp_0110', 'mp_0111', 'mp_0112', 'mp_0113', 'mp_0114',
  25.             'mp_0115', 'mp_0115a', 'mp_0115b', 'mp_0115c', 'mp_0115d',
  26.             'mp_0116', 'mp_0117', 'mp_0118', 'mp_0119',
  27.             'mp_1000a', 'mp_1000b', 'mp_1000c', 'mp_1000d',
  28.             'mp_1001a', 'mp_1001b', 'mp_1001c', 'mp_1001d',
  29.             'mp_1002a', 'mp_1002b',
  30.             'mp_1010', 'mp_1011',
  31.             'mp_1099', 'mp_1100',
  32.             'mp_2000b', 'mp_2000c',
  33.             'mp_2001a', 'mp_2001b', 'mp_2001c', 'mp_2001d',
  34.             'mp_2002a', 'mp_2002b', 'mp_2002d',
  35.             'mp_2010', 'mp_2099', 'mp_2100',
  36.             'mp_3000b', 'mp_3000c', 'mp_3000d',
  37.             'mp_3001a', 'mp_3001b', 'mp_3001c', 'mp_3001d',
  38.             'mp_3002a', 'mp_3002c', 'mp_3002d',
  39.             'mp_3003c', 'mp_3003d',
  40.             'mp_3099', 'mp_3100',
  41.             'mp_4000a', 'mp_4000c', 'mp_4000d',
  42.             'mp_4001a', 'mp_4001b', 'mp_4001c', 'mp_4001d',
  43.             'mp_4002a', 'mp_4002b', 'mp_4002c', 'mp_4002d',
  44.             'mp_4011', 'mp_4099', 'mp_4100',
  45.             'mp_5000', 'mp_5098', 'mp_5099', 'mp_5100', 'mp_5101',
  46.             'mp_5200', 'mp_5300',
  47.             'mp_6000', 'mp_6001', 'mp_6002', 'mp_6003',
  48.             'mp_6100', 'mp_6100d', 'mp_6200',
  49.             'mp_6300', 'mp_6301', 'mp_6302', 'mp_6303',
  50.             'mp_7020', 'mp_7098',
  51.             'mp_7099', 'mp_7099a', 'mp_7099b', 'mp_7099c',
  52.             'mp_7100', 'mp_7200',
  53.             'mp_8098', 'mp_8099', 'mp_8100', 'mp_8100b',
  54.             'noi', 'system']
  55.  
  56. def get_data(filename):
  57.     totalbytes = os.path.getsize(filename)
  58.     infile = open(filename, 'rb')
  59.     totalfiledata = infile.read(totalbytes)
  60.     infile.close()
  61.     return totalfiledata
  62.  
  63. def replacestr(origstr,replacestr,startpos,replacelen):
  64. #Returns a string with a replaced sub-string
  65. #origstr - the original string, replacestr = the string to replace
  66. #startpos - where the replacement string should go
  67. #replacelen - how many characters of the original string to replace
  68.     return origstr[:startpos] + replacestr + origstr[startpos+replacelen:]
  69.  
  70. def twos_comp(val, bits):
  71.     """compute the 2's compliment of int value val"""
  72.     if( (val&(1<<(bits-1))) != 0 ):
  73.         val = val - (1<<bits)
  74.     return val
  75.  
  76. def myprogram(filename):
  77.  
  78.     opcodes = ((0x07,2),(0x40,2),(0x3f,2),(0x41,0x14),
  79.                (0x98,2),(0xc9,8),(0x36,8),(0xce,8),
  80.                (0xC1,'special'))
  81.  
  82.     # Load input
  83.     inputdata = []
  84.     with open(filename + '.data','rb') as f:
  85.         for line in f:
  86.             line = line.translate(None,'\r\n')
  87.             line = line.split('\t')
  88.             if len(line) < 3:
  89.                 continue
  90.             if line[1] != '':
  91.                 line[1] = int(line[1],16)
  92.             if line[0] != '' and line[1] == '':
  93.                 pass
  94.             elif line[0] != '': #Line has a new opcode
  95.                 if line[1] in [op[0] for op in opcodes]:  #It's one of our opcodes
  96.                     if line[4] == "" and line[3] != "":
  97.                         print '%s: Blank opcode %s at %s.' % (filename, hex(line[1]), line[0])
  98.                     line[0] = int(line[0],16)
  99.                     inputdata.append(line[:3])
  100.                     inputdata[-1].append([line[4]]) #append column 5 as set
  101.             else:
  102.                 inputdata[-1][-1].append(line[4])
  103.  
  104.     filedata = get_data(filename + '.orig')
  105.  
  106.     # Load pointers (file header)
  107.     pointers = []
  108.     pos = 0x3C
  109.     EOF = struct.unpack('<I',filedata[pos:pos+4])[0]
  110.     while pos < EOF:
  111.         pointers.append([pos,struct.unpack('<I',filedata[pos:pos+4])[0]])
  112.         pos += 0x28
  113.  
  114.     # Load more pointers (relative pointers in opcodes)
  115.     relpointers = []
  116.     pos = 0
  117.     for opcode in ('\x7b\x80\xe0\x82','\x7c\x80\xe0\x82','\x7d\x80\xdd\x82',
  118.                    '\x80\x80\xdd\x82','\x81\x80\xdd\x82','\x83\x80\xdd\x82'):
  119.         while True:
  120.             pos = filedata.find(opcode,pos+1)
  121.             if pos == -1:
  122.                 break
  123.             if opcode[0] in ('\x7b','\x7c'):
  124.                 pos += 4
  125.                 pos += struct.unpack('<I',filedata[pos:pos+4])[0] + 6 #Jump past 82E0 opcode
  126.                 relpointers.append([pos,struct.unpack('<I',filedata[pos:pos+4])[0]])
  127.             elif opcode[0] in ('\x7d','\x80','\x81'):
  128.                 pos += 4
  129.                 val = struct.unpack('<I',filedata[pos:pos+4])[0]
  130.                 if opcode[0] == '\x80':
  131.                     val = twos_comp(val,32)
  132.                 relpointers.append([pos,val])
  133.             elif opcode[0] == '\x83':
  134.                 pos += 10 #Jump past 82DD opcode
  135.                 relpointers.append([pos,struct.unpack('<I',filedata[pos:pos+4])[0]])
  136.  
  137.     # Replace strings
  138.     offset = 0
  139.     for (count,(addr,op,name,lines)) in enumerate(inputdata):
  140.         addr += offset
  141.         text = ""
  142.         # Build the 0x82DF opcodes (that have strings in them)
  143.         if op == 0x07:
  144.             for line in lines:
  145.                 text += line + '\\n'
  146.             text = text[:-2]
  147.             text = '\xDF\x82' + struct.pack('<I',len(text)) + text
  148.         else:
  149.             for line in lines:
  150.                 text += '\xDF\x82' + struct.pack('<I',len(line)) + line
  151.         name = '\xDF\x82' + struct.pack('<I',len(name)) + name
  152.         if op in (0x40,0x98):
  153.             text = name + text
  154.         # Go to the start of the first DF opcode
  155.         # Then look for the end of the string list
  156.         for opcode, jumplen in opcodes:
  157.             if op == opcode:
  158.                 break
  159.         else:
  160.             print "Failed opcode lookup!"
  161.             quit()
  162.         if op == 0xC1:
  163.             addr += 2
  164.             for x in range(3):
  165.                 addr += 2
  166.                 datalen = struct.unpack('<I',filedata[addr:addr+4])[0]
  167.                 addr += datalen + 4
  168.         else:
  169.             addr += jumplen
  170.         startpos = addr
  171.         if filedata[addr] != '\xDF':
  172.             pdb.set_trace()
  173.             print 'Fail'
  174.             quit()
  175.         else:
  176.             while filedata[addr] == '\xDF':
  177.                 addr += struct.unpack('<I',filedata[addr+2:addr+6])[0] + 6
  178.         endpos = addr
  179.         origlen = endpos - startpos
  180.         newlen = len(text)
  181.         # Replace the string
  182.         filedata = replacestr(filedata,text,startpos,endpos-startpos)
  183.         # Update pointers
  184.         for i,(pointerpos,pointertgt) in enumerate(pointers):
  185.             if pointertgt > startpos:
  186.                 pointers[i][1] = pointertgt + newlen - origlen
  187.         # Update relative pointers
  188.         for i,(pointerpos,pointertgt) in enumerate(relpointers):
  189.             if pointertgt < 0:
  190.                 if pointerpos + pointertgt > startpos:
  191.                     relpointers[i][0] += newlen - origlen
  192.                 elif pointerpos > startpos:
  193.                     relpointers[i][0] += newlen - origlen
  194.                     relpointers[i][1] += -newlen + origlen
  195.             else:
  196.                 if pointerpos > startpos:
  197.                     relpointers[i][0] += newlen - origlen
  198.                 elif pointerpos + pointertgt > startpos:
  199.                     relpointers[i][1] += newlen - origlen
  200.         # Update offset
  201.         offset += newlen - origlen
  202.  
  203.     # Write-back pointers
  204.     for pointerpos, pointertgt in pointers:
  205.         pointertgt = struct.pack('<I',pointertgt)
  206.         filedata = replacestr(filedata,pointertgt,pointerpos,4)
  207.  
  208.     # Write-back relative pointers
  209.     for pointerpos, pointertgt in relpointers:
  210.         if pointertgt > -1:
  211.             pointertgt = struct.pack('<I',pointertgt)
  212.         else:
  213.             pointertgt = int(hex(pointertgt & 0xFFFFFFFF)[2:-1],16)
  214.             pointertgt = struct.pack('<I',pointertgt)
  215.         filedata = replacestr(filedata,pointertgt,pointerpos,4)
  216.  
  217.     # Write the output
  218.     outfile = open(filename + '.bin','wb')
  219.     outfile.write(filedata)
  220.     outfile.close()
  221.  
  222.     # Update data.lst
  223.     datasize = struct.pack('<I',len(filedata))
  224.     filedata = get_data('data.lst')
  225.     pos = filedata.find(filename + (8-len(filename))*'\x00',0xCD00)
  226.     filedata = replacestr(filedata,datasize,pos+8,4)
  227.  
  228.     outfile = open('data.lst','wb')
  229.     outfile.write(filedata)
  230.     outfile.close()
  231.  
  232. if __name__ == '__main__':
  233. ##    for testing in IDLE
  234. ##    sys.argv.append('mp_0000')
  235.     for filename in filelist:
  236.         myprogram(filename)
RAW Paste Data