foundry.smb3parse.util package#

Submodules#

foundry.smb3parse.util.code_edit module#

Module defines an abstract class that represents a code edit in ROM.

This CodeEdit will self verify that that the target memory location is correct by checking the surrounding code to make sure it matches.

class CodeEdit(rom: Rom, address: int, length: int, prefix: bytearray, postfix: bytearray)#

Bases: ABC, Generic[D]

Represents an area to edit to the ROM code.

Notes

This class handles reading and writing the data of a specific code area for possible code edits. It will also check the ROM to see if the target modification area has shifted due to other code modifications.

This is an abstract class. Implementing classes will need to define the read and write routines based on the type of code edit that needs to be done. The read/write routines use the Generic data type ‘D’ for their operations.

Generic type ‘D’ is the abstract representation of the edit value and not the literal data values (though they could be the same in some cases). See read/write for more details.

A potential improvement in the future would be to check if the target address is valid during initialization and if it isn’t, search the adjacent code areas (maybe 500 bytes or user specified) and try to find a matching prefix/postfix with the correct offsets. This would let this adapt to ROMs with code shifting modifications rather than rejecting them.

The above paragraph is particularly true for expanded ROMs where bank 30/31 will always be shifted so edits in those banks will fail more often than others. Another possible enhancement might be to read the ROM header as well to detect if the ROM is expanded to see if edits in banks 30/31 need to be shifted (instead of searched) as this would provide more accurate and quicker results. A search could be done secondary after the shift if the target code areas isn’t found in the shifted target location.

Attributes:
rom: Rom

The ROM to edit.

address: int

The address of the edit.

length: int

The length of the edit.

prefix: int

The ROM data just before the edit. This is used for checking the validity of the target location. This is useful for when a code edit has been made that has shifted the code and the target address is no longer valid. This will help protect invalid writes in that case.

postfix: int

The ROM data just after the edit. This is used for checking the validity of the target location. This is useful for when a code edit has been made that has shifted the code and the target address is no longer valid. This will help protect invalid writes in that case.

address: int#
is_valid() bool#

Verifies that both the prefix and postfix are valid.

Notes

This function can also be overwritten if only certain values are valid so that the value of the target area is also checked if that is important.

length: int#
postfix: bytearray#
prefix: bytearray#
abstract read() Optional[D]#

Read the abstract representation of the target edit area.

Notes

The Generic return type ‘D’ here is the abstract representation of the code edit, not the actual data of the edit, though in some situations these might be identical. For example, if we are checking if the players lives decrease when they die, the return value might be a string “infinite lives” or “vanilla” or True/False while the actual code edit might be the presence of an DEC NUM_LIVES instruction or a NOP section removing that code.

This is an Optional[D] because if the code area is invalid, no value might be returned.

rom: Rom#
abstract write(option: D)#

Read the abstract representation of the target edit area.

Notes

The Generic option type ‘D’ here is the abstract representation of the code edit, not the actual data of the edit, though in some situations these might be identical (see the read instruction documentation for an example).

The implementation of this function is responsible for taking the abstract input and generating the corresponding code edit.

foundry.smb3parse.util.code_edit_byte module#

Implements a concretion of the CodeEdit interface with a byte payload.

A single byte is the data type that is written to the specified address.

class CodeEditByte(rom: Rom, start_address: int, prefix: bytearray, postfix: bytearray)#

Bases: CodeEdit[int]

Edit a single byte of memory in the ROM.

read() int | None#

Reads the target byte out of the ROM.

This reads the byte at the target code address if both the prefix and postfix are valid. If they are not valid, returns None.

write(option: int)#

Writes the specified byte to the target address if valid.

If the prefix or postfix or not valid, the write is not allowed.

Throws OverflowError if a value larger than a byte is given.

foundry.smb3parse.util.code_edit_dict module#

Concrete implementation of the CodeEdit class using a dictionary lookup.

This CodeEdit uses a dictionary as the edit values. The keys represent the abstract option and the values are the byte data needing to be programmed into memory.

class CodeEditDict(rom: Rom, start_address: int, length: int, prefix: bytearray, options: dict, postfix: bytearray)#

Bases: CodeEdit[Any]

Represents a code edit that is specified by a dictionary.

The user passes in a dictionary of abstract labels (Any) in the keys and the corresponding bytearray to be written to memory in the value of the dictionary. The user can then request a read/write using the abstract key name.

is_option(option: Any) bool#
is_valid()#

Check to see if the current ROM code area is valid.

This calls the super() valid so the prefix and postfix are checked to see if they are valid. Additionally this will check to see if the value at the code edit location is in the provided dictionary.

read() Any | None#

Returns the abstract representation of target code area.

This will read the current value in the ROM at the target address location and covert it to the corresponding abstract representation provided by the user during initialization. If a matching abstract value isn’t found, None is returned.

write(option: Any)#

Requests a code edit by an abstract representation/name.

This will take the specified data, look it up in the provided dictionary and write the corresponding bytearray into the ROM at the target address location. If there is no matching abstract value in the dictionary, the write is rejected.

foundry.smb3parse.util.rom module#

class Rom(rom_data: bytearray)#

Bases: object

find(byte: bytes, offset: int = 0) int#
int(offset: int) int#
little_endian(offset: int) int#
read(offset: int, length: int) bytearray#
save_to(path: str)#
write(offset: int, data: bytes)#
write_little_endian(offset: int, integer: int)#

Module contents#

little_endian(two_bytes: bytearray) int#

Takes a byte array of length 2 and returns the integer it represents in little endian.