Background
<p dir="auto">The International Patching System (IPS) patch format is a historically popular distribution format for ROM hacks. It's a <a href="http://old.smwiki.net/wiki/IPS_file_format" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">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.
<p dir="auto">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 <code>pip install ips-util.
<h1>Links
<ul>
<li><a href="https://github.com/nleseul/ips_util" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Project GitHub repository
<li><a href="https://pypi.org/project/ips-util/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">PyPI page
<ul>
<li><a href="https://github.com/nleseul" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">My GitHub account
<h1>Usage notes
<p dir="auto">(Pretty much straight from the <a href="https://github.com/nleseul/ips_util/blob/master/README.md" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">README.)
<p dir="auto">To create a patch, using existing source and target binary files:
<pre><code>> ips_util create "Super Mario World.smc" "Super Mario World [1337357_h4x_3v4r].smc" -o 1337_p47ch.ips
<p dir="auto">To apply a patch to a binary file:
<pre><code>> ips_util apply 1337_p47ch.ips "Super Mario World.smc" -o w00t.smc
<p dir="auto">To dump the contents of a patch:
<pre><code>> ips_util trace 1337_p47ch.ips
<p dir="auto">The package can also be used within Python scripts to build IPS patches manually, as follows:
<pre><code>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:
f.write(patch.encode())
<h1>Testing
<p dir="auto">The package includes unit tests (contained in the <code>ips_util/tests/test_patch.py script) to verify design requirements and some common edge cases in IPS format:
<h2>Manually created patches
<ul>
<li>Verify that a basic patch produces the desired result (<code>test_patch_core)
<li>Verify that a change made past the end of the original data will pad the result data as needed (<code>test_patch_padding)
<li>Verify that the truncation syntax used by some IPS tools functions as intended (<code>test_patch_truncation)
<li>Verify that the library generates an error when the starting address of a patch record is exactly 0x454f46 ('EOF') (<code>test_patch_eof_edge_case)
<h2>Patches created from source and target binary data (the <code>Patch.create() API)
<ul>
<li>Verify that the patch created from binary data reproduces the desired target data when applied (<code>test_create_equal_length)
<li>Verify that creating a patch correctly handles padding when the target data is longer than the source data (<code>test_create_padded_length)
<ul>
<li>... even when the padded data contains only zeros. (<code>test_create_padded_length_all_zero)
<li>Verify that creating a patch correctly handles truncation when the target data is shorter than the source data (<code>test_create_truncated_length)
<li>Verify that when a difference occurs at the address 0x454f46, the generated patch shifts that address to avoid the EOF error noted above (<code>test_create_eof_edge_case)
<li>Verify that an error is generated when the binary data provided is longer than the maximum supported address (<code>test_create_address_overflow)
<li>Verify that when creating a patch, differences longer than the maximum supported size are handled gracefully (<code>test_create_size_overflow)
<ul>
<li>... even when the record is run-length encoded (<code>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?
<p dir="auto">From the documentation, I can see it is a complete and useful tool and good job for putting it on <code>pip. <ol> <li>It would be good to see some real ROM files in your test scripts e.g. you can put the ROM under <code>testdata directories. <li>When dealing with I/O, I feel that the try...catch is kinda missing. <li>It is better to group your commits into a PR. <li>If a binary file is empty, your <code>Path.load will probably throw exception? <li>You might want to add a command-line option to enable the debugger output. <p dir="auto">Your contribution has been evaluated according to <a href="https://join.utopian.io/guidelines" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category. <p dir="auto">To view those questions and the relevant answers related to your post, <a href="https://review.utopian.io/result/3/2-2-2-2-2-2-2-" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">click here. <hr /> <p dir="auto"><br /> Chat with us on <a href="https://discord.gg/uTyJkNm" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Discord.<br /> <a href="https://join.utopian.io/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">[utopian-moderator]<span>Need help? Write a ticket on <a href="https://support.utopian.io/" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">https://support.utopian.io/.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!
SteemPlus or Steeditor). Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via
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) :
<table><tr><td><span><img src="https://images.hive.blog/768x0/https://steemitimages.com/60x70/http://steemitboard.com/@nleseul/votes.png?201812261723" srcset="https://images.hive.blog/768x0/https://steemitimages.com/60x70/http://steemitboard.com/@nleseul/votes.png?201812261723 1x, https://images.hive.blog/1536x0/https://steemitimages.com/60x70/http://steemitboard.com/@nleseul/votes.png?201812261723 2x" /><td>You made more than 1250 upvotes. Your next target is to reach 1500 upvotes. <p dir="auto"><sub><em><a href="https://steemitboard.com/@nleseul" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Click here to view your Board<br /> <sub><em>If you no longer want to receive notifications, reply to this comment with the word <code>STOP <p dir="auto">To support your work, I also upvoted your post! <p dir="auto"><strong><span>Do not miss the last post from <a href="/@steemitboard">@steemitboard: <table><tr><td><a href="https://steemit.com/christmas/@steemitboard/christmas-challenge-send-a-gift-to-to-your-friends-the-party-continues" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link"><img src="https://images.hive.blog/768x0/https://steemitimages.com/64x128/http://i.cubeupload.com/kf4SJb.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/64x128/http://i.cubeupload.com/kf4SJb.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/64x128/http://i.cubeupload.com/kf4SJb.png 2x" /><td><a href="https://steemit.com/christmas/@steemitboard/christmas-challenge-send-a-gift-to-to-your-friends-the-party-continues" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Christmas Challenge - The party continues<tr><td><a href="https://steemit.com/christmas/@steemitboard/christmas-challenge-send-a-gift-to-to-your-friends" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link"><img src="https://images.hive.blog/768x0/https://steemitimages.com/64x128/http://i.cubeupload.com/kf4SJb.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/64x128/http://i.cubeupload.com/kf4SJb.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/64x128/http://i.cubeupload.com/kf4SJb.png 2x" /><td><a href="https://steemit.com/christmas/@steemitboard/christmas-challenge-send-a-gift-to-to-your-friends" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Christmas Challenge - Send a gift to to your friends <blockquote> <p dir="auto">Support <a href="https://steemit.com/@steemitboard" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">SteemitBoard's project! <strong><a href="https://v2.steemconnect.com/sign/account-witness-vote?witness=steemitboard&approve=1" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Vote for its witness and <strong>get one more award!Hi @nleseul!
Feel free to join our @steem-ua Discord serverYour 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!