72 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			72 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import bsdiff4
 | |
| import binascii
 | |
| import Utils
 | |
| 
 | |
| b2h = binascii.hexlify
 | |
| h2b = binascii.unhexlify
 | |
| 
 | |
| 
 | |
| class ROM:
 | |
|     def __init__(self, data, patches=None):
 | |
|         if patches:
 | |
|             for patch in patches:
 | |
|                 data = bsdiff4.patch(data, patch)
 | |
| 
 | |
|         self.banks = []
 | |
|         for n in range(0x40):
 | |
|             self.banks.append(bytearray(data[n*0x4000:(n+1)*0x4000]))
 | |
| 
 | |
|     def patch(self, bank_nr, addr, old, new, *, fill_nop=False):
 | |
|         new = h2b(new)
 | |
|         bank = self.banks[bank_nr]
 | |
|         if old is not None:
 | |
|             if isinstance(old, int):
 | |
|                 old = bank[addr:old]
 | |
|             else:
 | |
|                 old = h2b(old)
 | |
|             if fill_nop:
 | |
|                 assert len(old) >= len(new), "Length mismatch: %d != %d (%s != %s)" % (len(old), len(new), b2h(old), b2h(new))
 | |
|                 new += b'\x00' * (len(old) - len(new))
 | |
|             else:
 | |
|                 assert len(old) == len(new), "Length mismatch: %d != %d (%s != %s)" % (len(old), len(new), b2h(old), b2h(new))
 | |
|             assert addr >= 0 and addr + len(old) <= 16*1024
 | |
|             if bank[addr:addr+len(old)] != old:
 | |
|                 if bank[addr:addr + len(old)] == new:
 | |
|                     # Patch is already applied.
 | |
|                     return
 | |
|                 loc = bank.find(old)
 | |
|                 while loc > -1:
 | |
|                     print("Possible at:", hex(loc))
 | |
|                     loc = bank.find(old, loc+1)
 | |
|                 assert False, "Patch mismatch:\n%s !=\n%s at 0x%04x" % (b2h(bank[addr:addr+len(old)]), b2h(old), addr)
 | |
|         bank[addr:addr+len(new)] = new
 | |
|         assert len(bank) == 0x4000
 | |
| 
 | |
|     def fixHeader(self, *, name=None):
 | |
|         if name is not None:
 | |
|             name = name.encode("utf-8")
 | |
|             name = (name + (b"\x00" * 15))[:15]
 | |
|             self.banks[0][0x134:0x143] = name
 | |
| 
 | |
|         checksum = 0
 | |
|         for c in self.banks[0][0x134:0x14D]:
 | |
|             checksum -= c + 1
 | |
|         self.banks[0][0x14D] = checksum & 0xFF
 | |
| 
 | |
|         # zero out the checksum before calculating it.
 | |
|         self.banks[0][0x14E] = 0
 | |
|         self.banks[0][0x14F] = 0
 | |
|         checksum = 0
 | |
|         for bank in self.banks:
 | |
|             checksum = (checksum + sum(bank)) & 0xFFFF
 | |
|         self.banks[0][0x14E] = checksum >> 8
 | |
|         self.banks[0][0x14F] = checksum & 0xFF
 | |
| 
 | |
|     def save(self):
 | |
|         # don't pass the name to fixHeader
 | |
|         self.fixHeader()
 | |
|         return b"".join(self.banks)
 | |
| 
 | |
|     def readHexSeed(self):
 | |
|         return self.banks[0x3E][0x2F00:0x2F10].hex().upper()
 | 
