ndspy.rom
: ROMs¶
ndspy.rom
provides a class that represents a Nintendo DS ROM file.
Note
Unlike most ndspy documentation, the attributes of
NintendoDSRom
aren’t arranged mostly alphabetically. Rather,
they’re sorted in the same order as in ROM header data.
Examples¶
Change a ROM’s name and resave it:
>>> import ndspy.rom
>>> rom = ndspy.rom.NintendoDSRom.fromFile('nsmb.nds')
>>> print(rom.name)
bytearray(b'NEW MARIO')
>>> rom.name = b'Example Name'
>>> rom.saveToFile('nsmb_edited.nds')
>>>
Get a file from a ROM by file ID:
>>> import ndspy.rom
>>> rom = ndspy.rom.NintendoDSRom.fromFile('nsmb.nds')
>>> soundDataSDAT = rom.files[134]
>>> with open('sound_data.sdat', 'wb') as f:
... f.write(soundDataSDAT)
...
4839008
>>>
Replace a file in a ROM by filename, and resave it:
>>> import ndspy.rom
>>> rom = ndspy.rom.NintendoDSRom.fromFile('nsmb.nds')
>>> with open('sound_data.sdat', 'rb') as f:
... soundDataSDAT = f.read()
...
>>> rom.setFileByName('sound_data.sdat', soundDataSDAT)
>>> rom.saveToFile('nsmb_edited.nds')
>>>
Print the names of all NSBTX files, found by looking for their file data magics rather than file extensions:
>>> import ndspy.rom
>>> rom = ndspy.rom.NintendoDSRom.fromFile('nsmb.nds')
>>> rom.setFileByName('sound_data.sdat', soundDataSDAT)
>>> for i, file in enumerate(rom.files):
... if file.startswith(b'BTX0'):
... print(rom.filenames.filenameOf(i))
...
enemy/b_lift.nsbtx
enemy/d_bridge.nsbtx
enemy/I_do_hahen_l.nsbtx
enemy/I_do_hahen_r.nsbtx
enemy/I_kaiten_ami.nsbtx
[snip]
polygon_unit/wire_netting8.nsbtx
polygon_unit/wire_netting9.nsbtx
>>>
Load a ROM’s ARM9 code file and overlays:
>>> arm9 = rom.loadArm9()
>>> print(arm9)
<main-code at 0x02000000
<code-section at 0x02000000: b'\xff\xde\xff\xe7\xff\xde\xff\xe7\xff\xde\xff\xe7\xff\xde\x15\xa3\x82\xe5\x1d\1\xfa\x11\x1c%\x8a\td\x80\x19\xaf\xdc\x8d'... implicit>
<code-section at 0x01FF8000: b'\0\xc0\x90\xe5\40\x90\xe5H \x9f\xe5H\x10\x9f\xe5\0\xc0\x82\xe5\40\x82\xe5\x08\xc0\x90\xe5\x0c \x90\xe5'...>
<code-section at 0x027E0000: b'`\x81\xff\1`\x81\xff\1`\x81\xff\18\x83\xff\1H\x83\xff\1X\x83\xff\1h\x83\xff\1`\x81\xff\1'...>
<code-section at 0x02043380: b'\0\x10\x90\xe5\0\0Q\xe3\1\x10A\x12\0\x10\x80\x15\0\0\x90\xe5\x1e\xff/\xe1\xb0\x10\xd0\xe1\0\0Q\xe3'...>
<code-section at 0x02085880: b''>
>
>>> overlays = rom.loadArm9Overlays()
>>> for id, overlay in overlays.items():
... print(id, overlay)
...
0 <overlay at 0x020986E0 file=0 compressed verify-hash>
1 <overlay at 0x020CC2E0 file=5 compressed verify-hash>
2 <overlay at 0x020CC2E0 file=7 compressed verify-hash>
3 <overlay at 0x020CC2E0 file=9 compressed verify-hash>
4 <overlay at 0x020CC2E0 file=11 compressed verify-hash>
5 <overlay at 0x020CC2E0 file=12 compressed verify-hash>
[snip]
129 <overlay at 0x020B8920 file=27 compressed verify-hash>
130 <overlay at 0x021226E0 file=126 compressed verify-hash>
>>>
API¶
- class ndspy.rom.NintendoDSRom([data])¶
A Nintendo DS ROM file (.nds).
- Parameters:
data (bytes) – The data to be read as a ROM file. If not provided, the ROM will use default values.
- name¶
The ROM’s name. This is usually a short ASCII string containing the name of the software. This can be up to 12 bytes long; longer values will be truncated when saving.
This is at offset 0x000 in the ROM header.
- Type:
bytes
(12-byte limit)- Default:
b''
- idCode¶
The four-byte ID code of the software. Usually, this is ASCII, and the fourth character is a region identifier (“E” for North America, “P” for Europe, or “J” for Japan).
This is at offset 0x00C in the ROM header.
- Type:
bytes
(exactly 4 bytes long)- Default:
b'####'
- developerCode¶
An identifier for the developer of the software. Usually two ASCII characters; for example, Nintendo is “01”.
This is at offset 0x010 in the ROM header.
- Type:
bytes
(exactly 2 bytes long)- Default:
b'\0\0'
- unitCode¶
The systems this ROM supports:
0: Nintendo DS (DSi only in compatibility mode)
2: Both Nintendo DS and Nintendo DSi
3: Nintendo DSi only
This is at offset 0x012 in the ROM header.
- Type:
- Default:
0
- encryptionSeedSelect¶
The seed number to use when decrypting the ROM. The actual seed values are built into the DS’s hardware; this is only an index into a table. Valid values are 0 through 7, inclusive.
This is at offset 0x013 in the ROM header.
- Type:
- Default:
0
- deviceCapacity¶
A number representing the storage capacity of the hardware this ROM is intended to be placed on. The formula is
2 ^ (17 + X)
bytes; for example, a value of 7 means 16 MB.This is at offset 0x014 in the ROM header.
Note
This can optionally be recalculated for you automatically upon saving the ROM. For more information about this, see the documentation for the
save()
function.- Type:
- Default:
9
- region¶
The region this ROM is intended to be used in:
0x00: most regions
0x40: Korea
0x80: China
This is at offset 0x01D in the ROM header.
- Type:
- Default:
0
- version¶
The version number for this ROM. It’s unclear exactly what this means.
This is at offset 0x01E in the ROM header.
- Type:
- Default:
0
- autostart¶
A value related to how the ROM should be loaded. If “
autostart
& 4” is set, the “Press Button” message after the Health and Safety screen will be skipped.This is at offset 0x01F in the ROM header.
- Type:
- Default:
0
- arm9EntryAddress¶
The RAM address that ARM9 execution should begin at, after the ARM9 code has been loaded into RAM at
arm9RamAddress
.This is at offset 0x024 in the ROM header.
See also
arm9
– the code data that this entry address should reference.- Type:
- Default:
0x02000800
- arm9RamAddress¶
The RAM address that the ARM9 code should be loaded to.
This is at offset 0x028 in the ROM header.
See also
arm9
– the code data that will be loaded to this address.- Type:
- Default:
0x02000000
- arm7EntryAddress¶
The RAM address that ARM7 execution should begin at, after the ARM7 code has been loaded into RAM at
arm7RamAddress
.This is at offset 0x034 in the ROM header.
See also
arm7
– the code data that this entry address should reference.- Type:
- Default:
0x02380000
- arm7RamAddress¶
The RAM address that the ARM7 code should be loaded to.
This is at offset 0x038 in the ROM header.
See also
arm7
– the code data that will be loaded to this address.- Type:
- Default:
0x02380000
- normalCardControlRegisterSettings¶
The “port 0x040001A4 setting for normal commands”. For more information, see the section about this value on GBATEK (subheader “40001A4h - NDS7/NDS9 - ROMCTRL - Gamecard Bus ROMCTRL (R/W)”).
This is at offset 0x060 in the ROM header.
- Type:
- Default:
0x00416657
- secureCardControlRegisterSettings¶
The “port 0x040001A4 setting for KEY1 commands”. For more information, see the section about this value on GBATEK (subheader “40001A4h - NDS7/NDS9 - ROMCTRL - Gamecard Bus ROMCTRL (R/W)”).
This is at offset 0x064 in the ROM header.
- Type:
- Default:
0x081808f8
- secureAreaChecksum¶
The checksum of the encrypted “secure area” of the ROM.
This is at offset 0x06C in the ROM header.
Todo
This should be calculated automatically when saving the ROM instead of being an attribute.
- Type:
- Default:
0x0000
- secureTransferDelay¶
A delay value of some kind related to encryption commands. Measured in units of 130.912kHz each. For more information, see the section about this value on GBATEK (subheader “Secure Area Delay”).
This is at offset 0x06E in the ROM header.
- Type:
- Default:
0x0D7E
- arm9CodeSettingsPointerAddress¶
The address in RAM (plus 4) of a pointer to the “code settings” structure in ARM9’s main code file. This defines things like the SDK version used to compile the ROM, whether the code is compressed or not, and the list of ARM9 code “sections” and where they should be placed in memory. If this value is 0, then either there is no code settings block in ARM9 or its location is unspecified.
This is at offset 0x070 in the ROM header.
Note
You have to subtract 4 from this value to get the actual address of the pointer to the code settings block.
- Type:
- Default:
0
- arm7CodeSettingsPointerAddress¶
The address in RAM (plus 4) of a pointer to the “code settings” structure in ARM7’s main code file. This defines things like the SDK version used to compile the ROM, whether the code is compressed or not, and the list of ARM7 code “sections” and where they should be placed in memory. If this value is 0, then either there is no code settings block in ARM7 or its location is unspecified.
This is at offset 0x074 in the ROM header.
Note
You have to subtract 4 from this value to get the actual address of the pointer to the code settings block.
- Type:
- Default:
0
- secureAreaDisable¶
This value disables the encrypted “secure area” of the ROM, allowing one to use that area without encryption. To do this, the value must be set to “NmMdOnly”, encrypted. This is probably impossible without Nintendo’s private keys.
This is at offset 0x078 in the ROM header.
- Type:
bytes
(exactly 8 bytes long)- Default:
b'\0\0\0\0\0\0\0\0'
- pad088¶
Padding area beginning at 0x088 in the ROM header.
- Type:
bytes
(exactly 0x38 bytes long)- Default:
b'\0' * 0x38
- nintendoLogo¶
A compressed image of the Nintendo logo. The DS will refuse to load the ROM if this is modified in any way.
This is at offset 0x0C0 in the ROM header.
- Type:
bytes
(exactly 0x9C bytes long)- Default:
(the correct value)
- debugRomAddress¶
The address where the “debug rom” should be loaded to in RAM, if present. It’s unclear what exactly this is.
This is at offset 0x168 in the ROM header.
See also
debugRom
– the data this refers to.- Type:
- Default:
0
- pad16C¶
Padding area beginning at 0x16C in the ROM header.
- Type:
bytes
(exactly 0x94 bytes long)- Default:
b'\0' * 0x94
- rsaSignature¶
The ROM’s RSA signature data. Not every ROM has is cryptographically signed, but for those that are, this is stored at the very end of the ROM. Since most methods of playing games from ROM files these days bypass the RSA verification step, this attribute probably isn’t very useful for most purposes.
- Type:
bytes
(either 0 or 0x88 bytes long)- Default:
b''
- arm9¶
The main ARM9 executable binary to be loaded to
arm9RamAddress
.See also
ndspy.code.MainCodeFile
– the ndspy class you can use to load this data.arm9RamAddress
– the address this will be loaded to in RAM.arm9EntryAddress
– the address in RAM where ARM9 execution will begin.- Type:
- Default:
b''
- arm9PostData¶
A small amount of extra data immediately following
arm9
in the ROM data. It is unclear what this is for.- Type:
- Default:
b''
- arm7¶
The main ARM7 executable binary to be loaded to
arm7RamAddress
.See also
ndspy.code.MainCodeFile
– the ndspy class you can use to load this data.arm7RamAddress
– the address this will be loaded to in RAM.arm7EntryAddress
– the address in RAM where ARM7 execution will begin.- Type:
- Default:
b''
- arm9OverlayTable¶
The table containing information about ARM9 overlays.
See also
ndspy.code.loadOverlayTable()
– the ndspy function you can use to load this data.- Type:
- Default:
b''
- arm7OverlayTable¶
The table containing information about ARM7 overlays.
See also
ndspy.code.loadOverlayTable()
– the ndspy function you can use to load this data.- Type:
- Default:
b''
- iconBanner¶
A structure containing the game’s icon data, and its title in multiple languages. For more information, see the section about this value on GBATEK.
The required length of this
bytes
object depends on its version number (which is its first two bytes), according to the following table:Version number
iconBanner
length0x0001
0x0840
0x0002
0x0940
0x0003
0x1240
0x0103
0x23C0
An empty bytes object (
b''
) is also allowed, which corresponds to a null icon/banner data offset in the ROM’s header.- Type:
bytes
(required length depends on the version number).- Default:
b''
- debugRom¶
Some optional data related to debugging; it’s unclear what exactly this is.
See also
debugRomAddress
– the address in RAM this will be loaded to.- Type:
- Default:
b''
- filenames¶
The root folder of the ROM’s filename table. These filenames usually do not cover all files in the ROM (for example, overlays are usually unnamed).
See also
ndspy.fnt
– the ndspy module thendspy.fnt.Folder
class resides in.files
– the corresponding list of files that these filenames refer to.- Type:
- Default:
ndspy.fnt.Folder()
- files¶
The list of files in this ROM. Indices are file IDs; that is, “
files
[0]” is the file with file ID 0, “files
[1]” is the file with file ID 1, etc.See also
filenames
– the set of filenames for these files.
- sortedFileIds¶
For unknown reasons, ROMs sometimes store files in an order other than that of ascending file IDs. To preserve this order, this list contains file IDs in the order in which they should be saved in the ROM data. This is automatically populated when opening a ROM, and you should never really need to change this. (You can empty it to force files to be saved in order, though.)
If any file IDs are missing from this list, they will be placed in order of ascending file IDs after the files that are in the list. If this is empty, all files will be saved in order of ascending file IDs.
See also
files
– the list of files these indices refer to.
- classmethod fromFile(filePath)¶
Load a ROM from a filesystem file. This is a convenience function.
- Parameters:
filePath (
str
or other path-like object) – The path to the ROM file to open.- Returns:
The ROM object.
- Return type:
- getFileByName(filename)¶
Return the data for the file with the given filename (path). This is a convenience function; the following two lines of code are exactly equivalent (apart from some error checking):
fileData = rom.getFileByName(filename) fileData = rom.files[rom.filenames.idOf(filename)]
See also
setFileByName()
– to replace the file data instead of retrieving it.
- setFileByName(filename, data)¶
Replace the data for the file with the given filename (path) with the given data. This is a convenience function; the following two lines of code are exactly equivalent (apart from some error checking):
rom.setFileByName(filename, fileData) rom.files[rom.filenames.idOf(filename)] = fileData
See also
getFileByName()
– to retrieve the file data instead of replacing it.
- loadArm7()¶
Create a
ndspy.code.MainCodeFile
object representing the main ARM7 code file in this ROM.See also
arm7
– depending on what you’re trying to do, it may be more appropriate to just use this raw data attribute directly instead.- Returns:
The ARM7 code file.
- Return type:
- loadArm7Overlays([idsToLoad])¶
Create a dictionary of this ROM’s ARM7
ndspy.code.Overlay
s.See also
arm7OverlayTable
– if you just want the raw overlay table data, you can access it from this attribute instead. This avoids the side effect of decompressing all of the overlay data (which can be slow).- Parameters:
idsToLoad (
set
ofint
) – A specific set of overlay IDs to load. You can use this to avoid loading overlays you don’t actually care about, in order to improve your application’s performance.- Returns:
A
dict
of overlays.- Return type:
dict
:{overlayID: overlay}
(whereoverlayID
is of typeint
andoverlay
is of typeOverlay
)
- loadArm9()¶
Create a
ndspy.code.MainCodeFile
object representing the main ARM9 code file in this ROM.See also
arm9
– depending on what you’re trying to do, it may be more appropriate to just use this raw data attribute directly instead.- Returns:
The ARM9 code file.
- Return type:
- loadArm9Overlays([idsToLoad])¶
Create a dictionary of this ROM’s ARM9
ndspy.code.Overlay
s.See also
arm9OverlayTable
– if you just want the raw overlay table data, you can access it from this attribute instead. This avoids the side effect of decompressing all of the overlay data (which can be slow).- Parameters:
idsToLoad (
set
ofint
) – A specific set of overlay IDs to load. You can use this to avoid loading overlays you don’t actually care about, in order to improve your application’s performance.- Returns:
A
dict
of overlays.- Return type:
dict
:{overlayID: overlay}
(whereoverlayID
is of typeint
andoverlay
is of typeOverlay
)
- save(*[, updateDeviceCapacity=False])¶
Generate file data representing this ROM.
- Parameters:
updateDeviceCapacity (bool) –
If this is
True
,deviceCapacity
will be updated based on the size of the output file data. It will be set to match the capacity of the smallest cartridge that would be able to hold the data.- default:
False
- Returns:
The ROM file data.
- Return type:
- saveToFile(filePath, *[, updateDeviceCapacity=False])¶
Generate file data representing this ROM, and save it to a filesystem file. This is a convenience function.
- Parameters:
filePath (
str
or other path-like object) – The path to the ROM file to save to.updateDeviceCapacity (bool) –
If this is
True
,deviceCapacity
will be updated based on the size of the output file data. It will be set to match the capacity of the smallest cartridge that would be able to hold the data.- default:
False