Advertisement
Guest User

QB EBOOT Insert v2

a guest
Feb 6th, 2016
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.13 KB | None | 0 0
  1. #v2:Support {} IDs for ascii encode fields
  2. import binascii
  3. import os
  4. import shutil
  5. import struct
  6.  
  7. INPUT_COL = 2
  8. PTR_COL = 3
  9. s1 = " .,'!?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~-&>():;/%"
  10. s2 = " .,’!?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~‐&>():;/%"
  11. translate_table = str.maketrans(s1, s2)    #For converting between ASCII and fullwidth SHIFT-JIS characters
  12.  
  13. def is_hex(n):
  14.     try:
  15.         int(n, 16)
  16.     except ValueError:
  17.         return False
  18.     return True
  19.  
  20. def text_decode(s, encoding='ascii', translate = True):
  21.     out = b''
  22.     while '"' in s:
  23.         s = s.replace('"', '“', 1)
  24.         s = s.replace('"', '”', 1)
  25.     while '{' in s:
  26.         if translate == True:
  27.             out += s[:s.find('{')].translate(translate_table).encode(encoding)
  28.         else:
  29.             out += s[:s.find('{')].encode(encoding)
  30.         code_pos = s.find('{')+1
  31.         code_end = s.find('}')
  32.         if code_end == -1:
  33.             print('decode error')
  34.             quit()
  35.         out += s[code_pos:code_end].encode('ascii')
  36.         s = s[code_end+1:]
  37.     if translate == True:
  38.         out += s.translate(translate_table).encode(encoding)
  39.     else:
  40.         out += s.encode(encoding)
  41.     return out
  42.  
  43. def load_input(filename):
  44.     inputdata = []
  45.     with open(filename, 'r', encoding='utf-8') as f:
  46.         for line in f:
  47.             line = line.rstrip('\r\n').split('\t')
  48.             if line[0] != '':               #New entry
  49.                 ptrs = []
  50.                 for ptr in line[PTR_COL:]:  
  51.                     if is_hex(ptr):
  52.                         ptr = int(ptr, 16)
  53.                     else:                   #End of pointer list
  54.                         break
  55.                     ptrs.append(ptr)
  56.                 inputdata.append([int(line[0], 16), line[INPUT_COL], ptrs]) #addr, text, ptrs
  57.             else:                           #Additional line for same entry
  58.                 inputdata[-1][1] += '\x0a' + line[INPUT_COL]
  59.     return inputdata
  60.  
  61. if os.path.isfile('EBOOT.orig'):    #This is to create a copy of the original (for running tool multiple times)
  62.     pass
  63. elif os.path.isfile('EBOOT.BIN'):
  64.     shutil.copy('EBOOT.BIN', 'EBOOT.orig')
  65. else:
  66.     print('Missing EBOOT.bin.')
  67.     quit()
  68.  
  69. with open('EBOOT.orig', 'rb') as f:
  70.     filedata = bytearray(f.read())
  71.  
  72. #Insert SHIFT-JIS text (which is most of it)
  73. inputdata = load_input('SJIS.tsv')
  74. nextpos = 0x16CE00                          #Start of extra data (expanded EBOOT)
  75. for addr, text, ptrs in sorted(inputdata, key=lambda x: x[0], reverse=True):
  76. #Go backwards (reverse = True) // key is addr - we want to do later lines first
  77.     endpos = filedata.find(b'\x00', addr)   #Find end of string
  78.     while filedata[endpos] == 0:            #Find start of next string
  79.         endpos += 1
  80.     endpos -= 2                             #Need 2 nulls (at least) for SJIS terminator (I think)
  81.     avail_space = endpos - addr            
  82.     text = text_decode(text, encoding='cp932')
  83.     if len(text) > avail_space:                         #NOT enough space
  84.         filedata[addr:endpos] = b'\x00' * avail_space   #Blank out the line
  85.         text += b'\x00' * 2                             #Add terminator
  86.         while len(text) % 4 != 0:                       #Align to word boundary
  87.             text += b'\x00'
  88.         filedata[nextpos:nextpos+len(text)] = text      #Insert text
  89. #Compute virtual address (vaddr) - 0x89C4200 is the difference between file
  90. #image position and virtual address for text in the EBOOT extra data area
  91.         vaddr = nextpos + 0x89C4200
  92.         for ptr in ptrs:
  93.             if ptr > 0x08000000:                        #Virtual address specified in input
  94. #0x8803F8C is the difference between file image position and virtual address
  95. #for text in the original EBOOT area (not the extra data section)
  96.                 vaddr_orig = addr + 0x8803F8C          
  97.                 if (vaddr & 0xFFFF) > 0x8000:           #Accomodate addiu instructions (all of them are addiu)
  98.                     vaddr += 0x10000
  99.                 ptr = ptr - 0x8803F8C                   #Find file address of ptr
  100.                 filedata[ptr:ptr+2] = struct.pack('<H', vaddr >> 16)        #Write high bytes
  101.                 ptr = filedata.find(struct.pack('<H', vaddr_orig & 0xFFFF),
  102.                                     ptr)                                    #Search for original low bytes
  103.                 if ptr % 4 != 0:                                            #Error on search misses (was really for debugging)
  104.                     print('{} Error: ptr={}, searchedfor={}'.format( \
  105.                         hex(addr), hex(ptr),  binascii.hexlify(struct.pack('<H', vaddr_orig & 0xFFFF))))
  106.                 filedata[ptr:ptr+2] = struct.pack('<H', vaddr & 0xFFFF)     #Write low bytes
  107.             else:                                       #File address specified in input (this is a lot simpler)
  108.                 ptr += 0x20                             #Accomodate 0x20 added for new program header in EBOOT
  109.                 filedata[ptr:ptr+4] = struct.pack('<I', vaddr)              #Write the pointer
  110.         nextpos += len(text)                            #Update state (position next text should go)
  111.     else:                                               #THERE IS enough space
  112.         text += b'\x00' * (avail_space - len(text))     #Pad the text out to the right length
  113.         filedata[addr:endpos] = text                    #Replace the text
  114. #Insert UTF-8 text
  115. inputdata = load_input('UTF8.tsv')
  116. for addr, text, ptrs in inputdata:
  117.     endpos = filedata.find(b'\x00', addr)   #Find end of string
  118.     avail_space = endpos - addr
  119.     text = text_decode(text, encoding='utf-8', translate=False)
  120.     if len(text) > avail_space:
  121.         print('{} too long. Text len={}, avail space={}'.format(hex(addr), len(text), avail_space))
  122.     else:
  123.         text = text + b'\x00' * (avail_space - len(text))
  124.         filedata[addr:endpos] = text
  125. with open('EBOOT.BIN', 'wb') as f:
  126.     f.write(filedata)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement