rpatcher
TypeScript icon, indicating that this package has built-in type declarations

0.1.0 • Public • Published

Logo

RomPatcher.ts

Zero-dependency JS ROM patching library for browsers

Installable (PWA) Web Demo

RomPatcher.ts is a re-write of MarcroBledo's RomPatcher.js - providing modularity, typing & simplicity.

To install, run

npm install rompatcher-ts

As of now, only Browsers are supported. For Node support, check out node-rompatcher on Gitlab.

Supported Formats

  • BPS
  • UPS
  • IPS

PR Contributions for more formats are welcome.

Usage

import Patcher from 'rompatcher-ts';

// 1. Initialize a patcher instance with a format.
const patcher = new Patcher([
  new IPSPattern,
  new BPSPattern,
  new UPSPattern
]);

// 2. Load ROM file
patcher.setROMFile(romFile);

// 3. Load Patch file asynchronously (2 & 3 can be interchanged)
try {
  await patcher.setPatchFile(patchFile)
} catch(e) {
  // Cannot recognize type of patch file
}

// This returns the pattern that will be used - i.e. IPS
// Must be called after patch file is loaded.
const patternToUse: string = patcher.pattern;

// 4. Load files asynchronously
await patcher.loadFiles();

// 5. Parse files
patcher.parseFile();

// 6. Patch the ROM
const resultPreparedFile = patcher.patch();

// 7. The blob can be obtained by calling export() on the resulting PreparedPatchFile.
const resBlob: Blob = resultPreparedFile.export();

API & Helpers

Patcher Patcher.ts

  • constructor(patternsToLoad: IPatchPattern[])
    Initialize a patcher instance with the patterns to be used.

  • async setPatchFile(patchFile: File): Promise<void>
    Asynchronously sets a patch file, which determines the type of the patch file supplied. If it is not recognized, it throws an Error.

  • setROMFile(romFile: File)
    Sets a ROM file to be patched

  • async loadFiles()
    Asynchronously loads the supplied ROM file & patch file into the stateful supplied pattern. Throws an error if both are not supplied.

  • parseFile()
    Parses the supplied ROM file & patch file with the supplied pattern. Throws an error if both are not supplied.

  • patch(validateStrictly = false) (Do not change validateStrictly)
    Patches the ROM file with the patch file, returning a PreparedPatchFile instance with the resulting file.

Utils utils/crc.ts

  • crc32Table()
    Generates a CRC32 table. Caching recommended.

  • crc32(preparedPatcherFile: PreparedPatchFile, headerSize: number | boolean, ignoreLastFourBytes: boolean)
    Uses a CRC32 table to return a crc32 value for checksum purposes.

PreparedPatchFile utils.ts

  • static async create(file: File)
    Asynchronously create an instance of a PreparedPatchFile, using the load function.

  • static createEmpty(size: number)
    Ccreate an instance of a PreparedPatchFile, Create an empty PreparedPatchFile with the size of the provided integer.

  • async load(file: File)
    Asynchronously load the supplied file, which creates an internal Uint8Array byte array of the data.

  • public copyTo(target: PreparedPatchFile, offsetSource: number, length?: number, offsetTarget: number = offsetSource)
    Copy the current instance to the target.

  • seek(offset: number)
    Set internal offset to offset.

  • skip(offset: number)
    Skip internal offset by the value of offset.

  • slice(offset: number, length?: number)
    Create a copy of the current file, starting from the offset of the current file with the length of the provided number. Returns the new file.

  • isEOF()
    Returns if the internal offset counter is at the end of file.

  • readString(len: number)
    Reads the string of byte array. Adds to internal offset counter by len.

  • readBytes(len: number)
    Reads the bytes of the byte array. Adds to internal offset counter by len.

  • writeBytes(len: number)
    Reads the bytes of the byte array. Adds to internal offset counter by len.

  • read/writeU*(forceLittleEndian?: boolean = false)
    Reads or writes bits. forceLittleEndian options are for U16 and higher. Increases the internal offset counter by bytes read or written.

  • export()
    Returns a Blob of the current instance.

Writing Patterns

All patterns extend IPatchPattern, where you must implement these methods:

interface IPatchPattern {
  // Magic string for patch formats - i.e. BPS - "BPS1"
  MAGIC: string;

  // Constructor. Load the rom file & the patch file here, using
  // PreparedPatchFile.create(romFile | patchFile) here.
  // Initialize class variables here too.
  // Load the romFile and the patchFile as a class variable.
  init(romFile: File, patchFile: File): void;

  // Parse the patch file - current implementations use an array
  // to go through the Uint8Array and digest it to array of records or actions.
  parse(): void;

  // Create an output file with createEmpty(), and using the array of
  // records/actions created in parse(), write to the output file.
  // This varies by format.
  patch(strictValidation?: boolean): PreparedPatchFile;

  // Uses header to check if it belongs to the pattern.
  belongsTo(header: string): boolean;

  // Name of the patch - i.e. ups - "ups"
  name(): string;
}

Refer to implemented examples and MarcroBledo's RomPatcher.js.

Contributing

  • Run prettier
  • Respect ESLint rules
  • Testing before creating a PR. Unfortunately, tests cannot be done due to licensing issues for Nintendo ROMs.
  • For changing content inside /docs/ folder (which is the demo app), run npm run docs:build before pushing.

Examples

View the source code for the web demo in the docs/ directory, or go here for the installable live demo.

License

This library is licensed under GPLv3.

Package Sidebar

Install

npm i rpatcher

Weekly Downloads

10

Version

0.1.0

License

GPL-3.0-or-later

Unpacked Size

164 kB

Total Files

52

Last publish

Collaborators

  • dragonsnapx