[utopian-io] ips-util - Python package for manipulating IPS patches

in #utopian-io2 years ago


The International Patching System (IPS) patch format is a historically popular distribution format for ROM hacks. It's a very simple format, and a number of tools exist for creating IPS patches from binary data. I wanted to be able to create IPS patches programatically in Python scripts, however, and no existing library provided that support. So I made one.

I got enough testing and polish done on the library that I chose to upload it to PyPI as a formal Python package. As such, a released version can be acquired by any Python user with pip install ips-util.


Usage notes

(Pretty much straight from the README.)

To create a patch, using existing source and target binary files:

> ips_util create "Super Mario World.smc" "Super Mario World [1337357_h4x_3v4r].smc" -o 1337_p47ch.ips

To apply a patch to a binary file:

> ips_util apply 1337_p47ch.ips "Super Mario World.smc" -o w00t.smc

To dump the contents of a patch:

> ips_util trace 1337_p47ch.ips

The package can also be used within Python scripts to build IPS patches manually, as follows:

from ips_util import Patch

def this_is_my_patch():
  patch = Patch()
  patch.add_record(0x1234, 999.to_bytes(2, byteorder='little')) # Max out some stat
  patch.add_rle_record(0x5678, b'\xea', 0x10)                   # NOP out a bunch of code
  with open('gavroche.ips', 'w+b') as f:


The package includes unit tests (contained in the ips_util/tests/test_patch.py script) to verify design requirements and some common edge cases in IPS format:

Manually created patches

  • Verify that a basic patch produces the desired result (test_patch_core)
  • Verify that a change made past the end of the original data will pad the result data as needed (test_patch_padding)
  • Verify that the truncation syntax used by some IPS tools functions as intended (test_patch_truncation)
  • Verify that the library generates an error when the starting address of a patch record is exactly 0x454f46 ('EOF') (test_patch_eof_edge_case)

Patches created from source and target binary data (the Patch.create() API)

  • Verify that the patch created from binary data reproduces the desired target data when applied (test_create_equal_length)
  • Verify that creating a patch correctly handles padding when the target data is longer than the source data (test_create_padded_length)
    • ... even when the padded data contains only zeros. (test_create_padded_length_all_zero)
  • Verify that creating a patch correctly handles truncation when the target data is shorter than the source data (test_create_truncated_length)
  • Verify that when a difference occurs at the address 0x454f46, the generated patch shifts that address to avoid the EOF error noted above (test_create_eof_edge_case)
  • Verify that an error is generated when the binary data provided is longer than the maximum supported address (test_create_address_overflow)
  • Verify that when creating a patch, differences longer than the maximum supported size are handled gracefully (test_create_size_overflow)
    • ... even when the record is run-length encoded (test_create_rle_size_overflow)

Thank you for your contribution. I am a fan of the vintage game consoles e.g. 8-bit super mario. So does this utility work on 8-bit ROM files?

From the documentation, I can see it is a complete and useful tool and good job for putting it on pip.

  1. It would be good to see some real ROM files in your test scripts e.g. you can put the ROM under testdata directories.
  2. When dealing with I/O, I feel that the try...catch is kinda missing.
  3. It is better to group your commits into a PR.
  4. If a binary file is empty, your Path.load will probably throw exception?
  5. You might want to add a command-line option to enable the debugger output.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.

Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.

Thank you for your review, @justyy! Keep up the good work!

Hey, @nleseul!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Congratulations @nleseul! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You made more than 1250 upvotes. Your next target is to reach 1500 upvotes.

Click here to view your Board
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Do not miss the last post from @steemitboard:

Christmas Challenge - The party continues
Christmas Challenge - Send a gift to to your friends

Support SteemitBoard's project! Vote for its witness and get one more award!

Hi @nleseul!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Coin Marketplace

STEEM 0.16
TRX 0.03
JST 0.025
BTC 12929.22
ETH 409.90
USDT 1.00
SBD 1.00