def ncsd_header(self, slot): """Retrieve NCSD header from rom on sdcard. This function retrieves the ncsd header from the specified rom on sdcard.""" self.fail_on_non_sky3ds() self.diskfp.seek(self.rom_list[slot][1]) return gamecard.ncsd_header(self.diskfp.read(0x1200))
def find_game(self, product_code): """Find a game on sdcard by product-code This function is used to automatically restore savegames to the right game. It basically gets the product-codes of all roms on sdcard and compares it to the given argument. Keyword Arguments: product_code -- product-code to look for on sdcard""" self.fail_on_non_sky3ds() slot = -1 rom_count = 0 for rom in self.rom_list: self.diskfp.seek(rom[1]) ncsd_header = gamecard.ncsd_header(self.diskfp.read(0x1200)) if ncsd_header['product_code'] == product_code: return (rom_count, ncsd_header) rom_count += 1 return (None, None)
def find_game(self, product_code): """Find a game on sdcard by product-code This function is used to automatically restore savegames to the right game. It basically gets the product-codes of all roms on sdcard and compares it to the given argument. Keyword Arguments: product_code -- product-code to look for on sdcard""" self.fail_on_non_sky3ds() slot = -1 rom_count = 0 for rom in self.rom_list: self.diskfp.seek(rom[1]) ncsd_header = gamecard.ncsd_header(self.diskfp.read(0x1200)) if ncsd_header['product_code'] == product_code: return (rom_count, ncsd_header) rom_count+=1 return (None, None)
def dump_savegame(self, slot, output): """Dump savegame from sdcard to file This code first looks at the actual game header of the rom in the specified slot to figure out if this is a Card1 or Card2 savegame based game. For Card1 savegames it just dumps the savegame from the preallocated region of Card1 savegames (0x100000 - 0x2000000, 31 each 0x100000 / 1MB). The savegame file has 'CTR_SAVE', the product code of the game, a mark that this is a Card1 savegame and some padding in front of the actual savegame data. For Card2 savegames it reads the writable_address from the games ncsd-header, and dumps 10MB from that location to a file. The savegame file also has 'CTR_SAVE', the product-code and a (different) mark in front of the actual savegame as well as the type and size of (emulated) game chip. Keyword Arguments: slot -- rom slot output -- output savegame file""" self.fail_on_non_sky3ds() if slot >= len(self.rom_list): raise Exception("Slot not found") self.diskfp.seek(0) self.diskfp.seek(self.rom_list[slot][1]) ncsd_header = gamecard.ncsd_header(self.diskfp.read(0x1200)) savegamefp = open(output, "wb") # 0x00 CTR_SAVE savegamefp.write(b'CTR_SAVE') # 0x08 Product Code savegamefp.write(bytearray( ncsd_header['product_code'].encode('ascii'))) # Zero-Padding + Save Type (0x00 = Card1, 0x01 = Card2) if ncsd_header['card_type'] == 'Card1': savegamefp.write(bytearray([0x00, 0x00])) else: savegamefp.write(bytearray([0x00, 0x01])) # Nand save offset / Writable Address self.diskfp.seek(self.rom_list[slot][1] + 0x200) savegamefp.write(self.diskfp.read(0x4)) # Unique ID (0x40 bytes but only 0x10 really used) self.diskfp.seek(self.rom_list[slot][1] + 0x1440) savegamefp.write(self.diskfp.read(0x40)) # Savegame Data if ncsd_header['card_type'] == 'Card1': # from card1 region (byte 1M - 32M on disk) self.diskfp.seek(0x100000 * (slot + 1)) savegamefp.write(self.diskfp.read(0x100000)) else: # from writable region in rom self.diskfp.seek(self.rom_list[slot][1] + ncsd_header['writable_address']) for i in range(0, 10): savegamefp.write(self.diskfp.read(0x100000)) savegamefp.close()
def dump_savegame(self, slot, output): """Dump savegame from sdcard to file This code first looks at the actual game header of the rom in the specified slot to figure out if this is a Card1 or Card2 savegame based game. For Card1 savegames it just dumps the savegame from the preallocated region of Card1 savegames (0x100000 - 0x2000000, 31 each 0x100000 / 1MB). The savegame file has 'CTR_SAVE', the product code of the game, a mark that this is a Card1 savegame and some padding in front of the actual savegame data. For Card2 savegames it reads the writable_address from the games ncsd-header, and dumps 10MB from that location to a file. The savegame file also has 'CTR_SAVE', the product-code and a (different) mark in front of the actual savegame as well as the type and size of (emulated) game chip. Keyword Arguments: slot -- rom slot output -- output savegame file""" self.fail_on_non_sky3ds() if slot >= len(self.rom_list): raise Exception("Slot not found") self.diskfp.seek(0) self.diskfp.seek(self.rom_list[slot][1]) ncsd_header = gamecard.ncsd_header(self.diskfp.read(0x1200)) savegamefp = open(output, "wb") # 0x00 CTR_SAVE savegamefp.write(b'CTR_SAVE') # 0x08 Product Code savegamefp.write(bytearray(ncsd_header['product_code'].encode('ascii'))) # Zero-Padding + Save Type (0x00 = Card1, 0x01 = Card2) if ncsd_header['card_type'] == 'Card1': savegamefp.write(bytearray([0x00, 0x00])) else: savegamefp.write(bytearray([0x00, 0x01])) # Nand save offset / Writable Address self.diskfp.seek(self.rom_list[slot][1] + 0x200) savegamefp.write(self.diskfp.read(0x4)) # Unique ID (0x40 bytes but only 0x10 really used) self.diskfp.seek(self.rom_list[slot][1] + 0x1440) savegamefp.write(self.diskfp.read(0x40)) # Savegame Data if ncsd_header['card_type'] == 'Card1': # from card1 region (byte 1M - 32M on disk) self.diskfp.seek(0x100000 * (slot + 1)) savegamefp.write(self.diskfp.read(0x100000)) else: # from writable region in rom self.diskfp.seek(self.rom_list[slot][1] + ncsd_header['writable_address']) for i in range(0, 10): savegamefp.write(self.diskfp.read(0x100000)) savegamefp.close()