From 355971c9a2a564809ff6a528ab0bfa9e04a687e6 Mon Sep 17 00:00:00 2001 From: Harrison <53527582+HTV04@users.noreply.github.com> Date: Sun, 28 Feb 2021 22:09:01 -0500 Subject: [PATCH] Finally fixed builder script and gba_db.bin The generated gba_db.bin now works with open_agb_firm! With a ton of help from profi200, I finally figured out the issue. Turns out open_agb_firm uses a binary search algorithm to find the hash from the gba_db.bin file. After a ton of (probably unnecessary) trial and error, I fixed my script so that it sorts the entries in the way open_agb_firm expects, and boom, it works! --- resources/gba_db.bin | Bin 674880 -> 674880 bytes tools/gba_db_builder/gba_db_builder.py | 72 ++++++++++++++++++------- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/resources/gba_db.bin b/resources/gba_db.bin index e001279b2f2ceda7e5fe49a2d61284e986ab4279..5d35e0518d03f0383b3e6256446104d08cc2fd3e 100644 GIT binary patch delta 20890 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 delta 19631 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 QTWUBgQ!}BkvB>26|2$~d>i_@% diff --git a/tools/gba_db_builder/gba_db_builder.py b/tools/gba_db_builder/gba_db_builder.py index a1cdeaf..9651b54 100644 --- a/tools/gba_db_builder/gba_db_builder.py +++ b/tools/gba_db_builder/gba_db_builder.py @@ -1,4 +1,4 @@ -# open_agb_firm gba_db.bin Builder v2.1 +# open_agb_firm gba_db.bin Builder v2.5 # By HTV04 # # This script parses MAME's gba.xml (found here: https://github.com/mamedev/mame/blob/master/hash/gba.xml) and converts it to a gba_db.bin file for open_agb_firm. @@ -7,22 +7,49 @@ # This script should work with any updates to MAME's gba.xml and the No-Intro DAT, unless something this script expects is changed. import math +import re +# import sys import xml.etree.ElementTree as ET # Use title, serial, SHA-1, size, and save type to generate gba_db entry as binary string -def gbadbentry(title, serial, sha, size, savetype): - entry = b'' +def gbadbentry(a, b, c, d, e): + entry = [] - entry += title.encode().ljust(200, b'\x00')[0:200] - entry += serial.encode().ljust(4, b'\x00')[0:4] - entry += bytes.fromhex(sha).ljust(20, b'\x00')[0:20] - entry += (int(math.log(size, 2)) << 27 | savetype).to_bytes(4, 'little') # Save type is stored weirdly + if len(c) != 40: + c = '0000000000000000000000000000000000000000' + cbytes = bytes.fromhex(c) + + entry.append(int.from_bytes(cbytes[:8], 'little')) # Sorting key + entry.append(a.encode().ljust(200, b'\x00')[:200]) + if len(b) != 4 or bool(re.search('[^A-Z0-9]', b)): + entry.append(b'\x00\x00\x00\x00') + else: + entry.append(b.encode()) + entry.append(cbytes) + entry.append((int(math.log(d, 2)) << 27 | e).to_bytes(4, 'little')) # Save type is stored weirdly return entry +# Prepare gba_db.bin binary string from gba_db list. +def preparegbadbbin(a): + gbadbbin = b'' + + # Use sort key to sort the gba_db list and delete it from each entry + a = sorted(a, key=lambda l:l[0]) + length = len(a) + for i in range(length): + a[i].pop(0) + + # Compile gba_db binary + for i in a: + for j in i: + gbadbbin += j + + return gbadbbin + if __name__ == '__main__': - gbadb = b'' + gbadb = [] skipcount = 0 count = 0 addcount = 0 @@ -30,7 +57,10 @@ if __name__ == '__main__': gba = ET.parse('gba.xml').getroot() # MAME gba.xml nointro = ET.parse('gba.dat').getroot() # No-Intro GBA DAT - addentries = False # Determine whether to include additional entries + # # Arguments + # if sys.argv[1] == 'noaddentries': # Don't include additional entries + # addentries = False + addentries = False # Leave as False for now since no additional entries have been added yet # Start adding entries for software in gba.findall('software'): @@ -52,8 +82,8 @@ if __name__ == '__main__': title = game.get('name') serial = rom.get('serial') - if serial in (None, 'N/A'): - serial = '\x00\x00\x00\x00' # If a serial can't be found, default to null bytes + if serial == None: + serial = '' size = int(rom.get('size')) # If not in No-Intro DAT, skip entry @@ -94,7 +124,7 @@ if __name__ == '__main__': continue # Expand gba_db with entry - gbadb += gbadbentry(title, serial, sha, size, savetype) + gbadb.append(gbadbentry(title, serial, sha, size, savetype)) print('Added entry "' + software.find('description').text + '"') count += 1 @@ -102,23 +132,27 @@ if __name__ == '__main__': # Add additional entries if addentries == True: # Example entries for demonstration purposes (to do: replace with valid entries) - gbadbentries = ([['AAAA - A', 'AAAA', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 0x1000000, 0], - ['BBBB - B', 'BBBB', 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', 0x1000000, 14], - ['CCCC - C', 'CCCC', 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC', 0x1000000, 15]]) + gbadbentries = ([['AAAA - A', 'AAAA', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 0x400000, 15], + ['BBBB - B', 'BBBB', 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB', 0x400000, 15], + ['CCCC - C', 'CCCC', 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC', 0x400000, 15]]) print() for title, serial, sha, size, savetype in gbadbentries: - gbadb += gbadbentry(title, serial, sha, size, savetype) + gbadb.append(gbadbentry(title, serial, sha, size, savetype)) print('Added additional entry "' + title + '"') addcount += 1 + print('\nFinalizing...\n') + + gbadbbin = preparegbadbbin(gbadb) + # Create and write to gba_db.bin with open('gba_db.bin', 'wb') as f: - f.write(gbadb) + f.write(gbadbbin) if addentries == True: - print('\n' + str(count) + ' entries added, ' + str(addcount) + ' additional entries added, ' + str(skipcount) + ' entries skipped') + print(str(count) + ' entries added, ' + str(addcount) + ' additional entries added, ' + str(skipcount) + ' entries skipped') else: - print('\n' + str(count) + ' entries added, ' + str(skipcount) + ' entries skipped') + print(str(count) + ' entries added, ' + str(skipcount) + ' entries skipped')