From 7144c399bf04368548252a448d474606f80c79c4 Mon Sep 17 00:00:00 2001 From: Jennifer Taylor Date: Mon, 4 Oct 2021 15:14:59 +0000 Subject: [PATCH] Add a project description file which includes code documentation. --- README.md | 4 +- arcadeutils/DESCRIPTION.md | 140 +++++++++++++++++++++++++++++++++++++ setup.py | 14 ++-- 3 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 arcadeutils/DESCRIPTION.md diff --git a/README.md b/README.md index ed0c9e3..e584d65 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ make the patch non-reversible. Arbitrary comments are supported anywhere in the Start a line with the `#` character to create a comment. Special values are recognized in comments. If you create a comment starting with `# File size:` then the the base file will be compared against the decimal number placed after the colon and any file -not matching that length will be rejected. +not matching that length will be rejected. If you create a comment starting with +`# Description` then all text after the colon will be seen as a description for the +whole patch. Various code uses this description as a patch title. Some examples are as follows: diff --git a/arcadeutils/DESCRIPTION.md b/arcadeutils/DESCRIPTION.md new file mode 100644 index 0000000..d88430f --- /dev/null +++ b/arcadeutils/DESCRIPTION.md @@ -0,0 +1,140 @@ +# arcadeutils + +Collection of utilities written in Python for working with various arcade binaries. +This is mostly suited towards the separated formats found in MAME archival releases +but also work on a variety of binaries from basically anywhere. It is fully typed +and requires a minimum of Python 3.6 to operate. + +## ByteUtil + +The ByteUtil class provides a series of handy ROM manipulation functions for combining +split ROMs and byteswapping ROMs. Use these when you are attempting to combine ROMs +that are dumped from multiple chips but are meant to be mapped to high and low bytes +in memory on a 16-bit or 32-bit arcade system. + +### ByteUtil.byteswap + +Takes a single byte argument "data", assumes that it is a 16-bit ROM where the upper and +lower bytes have been swapped and swaps them. Returns a new bytes object of the same +length where the upper and lower bytes of each 16-bit pair are swapped. + +### ByteUtil.wordswap + +Takes a single byte argument "data", assumes that it is a 32-bit ROM where each of the 32-bit +words is swapped. Returns a new bytes object of the same length where each 32-bit chunk +of bytes is swapped. + +## ByteUtil.combine16bithalves + +Takes two byte aruments "upper" and "lower" and assumes that these represent a ROM dump from +two 16-bit chips that are memory-mapped to a 32-bit word on the hardware they were dumped +from. Assembles them both into a single 32-bit ROM file where each 32-bit word is made +up of the 16-bit upper value and 16-bit lower value of the two inputs. + +## ByteUtil.combine8bithalves + +Takes two byte aruments "upper" and "lower" and assumes that these represent a ROM dump from +two 8-bit chips that are memory-mapped to a 16-bit word on the hardware they were dumped +from. Assembles them both into a single 16-bit ROM file where each half-word is made +up of the 8-bit upper value and 8-bit lower value of the two inputs. + +## BinaryDiff + +The BinaryDiff class provides a series of handy functions for manipulating binary data +based on a series of hex differences. It also provides functions for creating a series +of hex differences based on two identically-sized binaries. The format is designed to +be human-readable. + +### BinaryDiff.diff + +Given two identically-lengthed bytes arguments "bin1" and "bin2", returns a list of +patches that would need to be applied to "bin1" to convert it to "bin2". See the below +patch format for documentation as to what each list entry will look like. + +### BinaryDiff.size + +Given a list of patches as documented in the patch format section below, looks for a +"File Size" special comment and returns the value found. If no such section exists in +the list of patches it returns None. + +### BinaryDiff.description + +Given a list of patches as documented in the patch format section below, looks for a +"Description" special comment and returns the value found. If no such section exists in +the list of patches it returns None. + +### BinaryDiff.needed_amount + +Given a list of patches as documented in the patch format section below, examines the +list of patches and determines the minimum length of a binary that could be patched +by these patch bytes. Note that this ignores the "File Size" special comment and instead +focuses on the highest address of any byte changed by any single patch line. + +### BinaryDiff.can_patch + +Given a byte argument "binary" and a list of patches argument "patchlines", examines +the series of patches including the "File Size" comment and returns True if the binary +supplied could be patched by the patches supplied and False otherwise. Things that could +make a binary ineliglbe for patching include having the wrong file size, having not enough +bytes to patch or having incorrect bytes at a particular patch offset. If you pass in +the optional boolean keyword argument "reverse" set to True, this function will calculate +whether the reverse of the patch could instead be applied. If you pass in the optional +boolean keyword argument "ignore_size_differences" then the "File Size" comment will be +ignored. + +### BinaryDiff.patch + +Given a byte argument "binary" and a list of patches argument "patchlines", actually +perform the patches requested and return a new binary with the patches applied. If you +supply the optional boolean keyword argument "reverse" set to True, this function will +instead patch the reverse of each patch. A binary that was patched using `BinaryDiff.patch` +can be reverted back to the original format by calling `BinaryDiff.patch` again with +the "reverse" argument set to True. Note that the only restriction to this is if any of +the patches include wildcards then the resulting patched binary cannot be reversed. + +### Patch Format + +The patch format is simple. For each item in the patch list, the number on the left of +the colon is the hex offset where the difference was found, and the numbers on the right +are the hex values to find and replace. A wildcard (`*`) can be substituted for a hex +pair for any byte in the before section if you do not care what the value is, but be +aware that this will make the patch non-reversible. Arbitrary comments are supported +anywhere in the list of patches. If a list entry starts with the `#` character to it will +be seen as a comment. Special values are recognized in comments. If you create a comment +starting with `# File size:` then the the data length will be compared against the decimal +number placed after the colon and any file not matching that length will be rejected. +If you create a comment starting with `# Description` then all text after the colon will +be returned as the patch top level description. + +Some examples are as follows: + +A simple patch changing a byte in a file at offset `0x256` from `0xAA` to `0xDD`: + +``` +256: AA -> DD +``` + +That same patch, but only for files that are exactly 1024 bytes long: + +``` +# File size: 1024 +256: AA -> DD +``` + +A patch that does not care about one of the bytes it is patching. The byte at `0x513` +can be any value and the patch will still be applied, and altogether 4 bytes starting +at `0x512` will be changed to the hex value `0x00 0x11 0x22 0x33`: + +``` +512: AA * CC DD -> 00 11 22 33 +``` + +A patch with multiple offsets, and helpful author descriptions for each section: + +``` +# This part of the patch fixes a sprite offset issue. +128: AA -> BB + +# This part of the patch fixes sound playback issues. +256: 33 -> 44 +``` diff --git a/setup.py b/setup.py index 3b35a20..f732f40 100644 --- a/setup.py +++ b/setup.py @@ -2,19 +2,23 @@ import os from setuptools import setup # type: ignore +with open(os.path.join("arcadeutils", "DESCRIPTION.md"), "r", encoding="utf-8") as fh: + long_description = fh.read() + + setup( name='arcadeutils', - version='0.1.1', + version='0.1.2', description='Collection of utilities written in Python for working with various arcade binaries.', - long_description='Collection of utilities written in Python for working with various arcade binaries.', + long_description=long_description, + long_description_content_type="text/markdown", author='DragonMinded', + author_email='dragonminded@dragonminded.com', license='Public Domain', url='https://github.com/DragonMinded/arcadeutils', - package_data={"arcadeutils": ["py.typed"]}, + package_data={"arcadeutils": ["py.typed", "DESCRIPTION.md"]}, packages=[ 'arcadeutils', ], - install_requires=[ - ], python_requires=">=3.6", )