mirror of
https://github.com/marcrobledo/RomPatcher.js.git
synced 2025-06-27 16:25:54 +00:00
EBP support
This commit is contained in:
parent
df456bdfb9
commit
b052fdda13
6 changed files with 53 additions and 16 deletions
|
@ -3,8 +3,8 @@
|
||||||
<head>
|
<head>
|
||||||
<title>Rom Patcher JS</title>
|
<title>Rom Patcher JS</title>
|
||||||
<meta http-equiv="content-Type" content="text/html; charset=UTF-8"/>
|
<meta http-equiv="content-Type" content="text/html; charset=UTF-8"/>
|
||||||
<meta name="description" content="An online web-based ROM patcher. Supported formats: IPS, BPS, UPS, APS, RUP, PPF and xdelta."/>
|
<meta name="description" content="An online web-based ROM patcher. Supported formats: IPS, BPS, UPS, APS, RUP, PPF, EBP and xdelta."/>
|
||||||
<meta name="keywords" content="ips,ups,aps,bps,rup,ninja,ppf,xdelta,patcher,online,html5,web,rom,patch,hack,translation"/>
|
<meta name="keywords" content="ips,ebp,ups,aps,bps,rup,ninja,ppf,xdelta,patcher,online,html5,web,rom,patch,hack,translation"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
|
||||||
<link rel="manifest" href="./manifest.json"/>
|
<link rel="manifest" href="./manifest.json"/>
|
||||||
<link rel="shortcut icon" href="./webapp/app_icon_16.png" type="image/png" sizes="16x16"/>
|
<link rel="shortcut icon" href="./webapp/app_icon_16.png" type="image/png" sizes="16x16"/>
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
<meta name="twitter:domain" content="marcrobledo.com">
|
<meta name="twitter:domain" content="marcrobledo.com">
|
||||||
<meta property="og:title" content="Rom Patcher JS">
|
<meta property="og:title" content="Rom Patcher JS">
|
||||||
<meta name="twitter:title" content="Rom Patcher JS">
|
<meta name="twitter:title" content="Rom Patcher JS">
|
||||||
<meta name="twitter:description" content="An online web-based ROM patcher. Supported formats: IPS, BPS, UPS, APS, RUP, PPF and xdelta.">
|
<meta name="twitter:description" content="An online web-based ROM patcher. Supported formats: IPS, BPS, UPS, APS, RUP, PPF, EBP and xdelta.">
|
||||||
<meta property="og:image" content="https://www.marcrobledo.com/RomPatcher.js/webapp/thumbnail.jpg">
|
<meta property="og:image" content="https://www.marcrobledo.com/RomPatcher.js/webapp/thumbnail.jpg">
|
||||||
<meta name="twitter:image" content="https://www.marcrobledo.com/RomPatcher.js/webapp/thumbnail.jpg">
|
<meta name="twitter:image" content="https://www.marcrobledo.com/RomPatcher.js/webapp/thumbnail.jpg">
|
||||||
<meta name="twitter:card" content="photo">
|
<meta name="twitter:card" content="photo">
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
<div class="row m-b" id="rom-patcher-row-file-patch">
|
<div class="row m-b" id="rom-patcher-row-file-patch">
|
||||||
<div class="text-right"><label for="rom-patcher-input-file-patch" data-localize="yes">Patch file:</label></div>
|
<div class="text-right"><label for="rom-patcher-input-file-patch" data-localize="yes">Patch file:</label></div>
|
||||||
<div class="rom-patcher-container-input">
|
<div class="rom-patcher-container-input">
|
||||||
<input type="file" id="rom-patcher-input-file-patch" class="empty" accept=".ips,.ups,.bps,.aps,.rup,.ppf,.mod,.xdelta,.vcdiff,.zip" disabled />
|
<input type="file" id="rom-patcher-input-file-patch" class="empty" accept=".ips,.ups,.bps,.aps,.rup,.ppf,.mod,.ebp,.xdelta,.vcdiff,.zip" disabled />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row m-b" id="rom-patcher-row-patch-description">
|
<div class="row m-b" id="rom-patcher-row-patch-description">
|
||||||
|
@ -126,6 +126,7 @@
|
||||||
<option value="ups">UPS</option>
|
<option value="ups">UPS</option>
|
||||||
<option value="aps">APS</option>
|
<option value="aps">APS</option>
|
||||||
<option value="rup">RUP</option>
|
<option value="rup">RUP</option>
|
||||||
|
<option value="ebp">EBP</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
2
index.js
2
index.js
|
@ -58,7 +58,7 @@ program
|
||||||
.description('creates a patch based on two ROMs')
|
.description('creates a patch based on two ROMs')
|
||||||
.argument('<original_rom_file>', 'the original ROM')
|
.argument('<original_rom_file>', 'the original ROM')
|
||||||
.argument('<modified_rom_file>','the modified ROM')
|
.argument('<modified_rom_file>','the modified ROM')
|
||||||
.option('-f, --format <format>','patch format (allowed values: ips [default], bps, ppf, ups, aps, rup)')
|
.option('-f, --format <format>','patch format (allowed values: ips [default], bps, ppf, ups, aps, rup, ebp)')
|
||||||
.action(function(originalRomPath, modifiedRomPath, options) {
|
.action(function(originalRomPath, modifiedRomPath, options) {
|
||||||
console.log(options);
|
console.log(options);
|
||||||
try{
|
try{
|
||||||
|
|
|
@ -242,8 +242,8 @@ const RomPatcher = (function () {
|
||||||
format = 'ips';
|
format = 'ips';
|
||||||
|
|
||||||
var patch;
|
var patch;
|
||||||
if (format === 'ips') {
|
if (format === 'ips' || format === 'ebp') {
|
||||||
patch = IPS.buildFromRoms(originalFile, modifiedFile);
|
patch = IPS.buildFromRoms(originalFile, modifiedFile, format === 'ebp');
|
||||||
} else if (format === 'bps') {
|
} else if (format === 'bps') {
|
||||||
patch = BPS.buildFromRoms(originalFile, modifiedFile, (originalFile.fileSize <= 4194304));
|
patch = BPS.buildFromRoms(originalFile, modifiedFile, (originalFile.fileSize <= 4194304));
|
||||||
} else if (format === 'ppf') {
|
} else if (format === 'ppf') {
|
||||||
|
|
|
@ -1175,7 +1175,7 @@ const ZIPManager = (function (romPatcherWeb) {
|
||||||
|
|
||||||
const ZIP_MAGIC = '\x50\x4b\x03\x04';
|
const ZIP_MAGIC = '\x50\x4b\x03\x04';
|
||||||
|
|
||||||
const FILTER_PATCHES = /\.(ips|ups|bps|aps|rup|ppf|mod|xdelta|vcdiff)$/i;
|
const FILTER_PATCHES = /\.(ips|ebp|ups|bps|aps|rup|ppf|mod|xdelta|vcdiff)$/i;
|
||||||
//const FILTER_ROMS=/(?<!\.(txt|diz|rtf|docx?|xlsx?|html?|pdf|jpe?g|gif|png|bmp|webp|zip|rar|7z))$/i; //negative lookbehind is not compatible with Safari https://stackoverflow.com/a/51568859
|
//const FILTER_ROMS=/(?<!\.(txt|diz|rtf|docx?|xlsx?|html?|pdf|jpe?g|gif|png|bmp|webp|zip|rar|7z))$/i; //negative lookbehind is not compatible with Safari https://stackoverflow.com/a/51568859
|
||||||
const FILTER_NON_ROMS = /(\.(txt|diz|rtf|docx?|xlsx?|html?|pdf|jpe?g|gif|png|bmp|webp|zip|rar|7z))$/i;
|
const FILTER_NON_ROMS = /(\.(txt|diz|rtf|docx?|xlsx?|html?|pdf|jpe?g|gif|png|bmp|webp|zip|rar|7z))$/i;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,15 @@ const IPS_MAX_ROM_SIZE=0x1000000; //16 megabytes
|
||||||
const IPS_RECORD_RLE=0x0000;
|
const IPS_RECORD_RLE=0x0000;
|
||||||
const IPS_RECORD_SIMPLE=0x01;
|
const IPS_RECORD_SIMPLE=0x01;
|
||||||
|
|
||||||
|
/* There is also support for the EBP (EarthBound Patch) format here. */
|
||||||
|
/* EBP has no real specification, but an implementation is here: https://github.com/Lyrositor/EBPatcher */
|
||||||
|
/* EBP is actually just IPS with some JSON metadata stuck on the end. */
|
||||||
|
/* We can safely ignore this data when applying patches. */
|
||||||
|
/* When creating patches, insert this data after everything else. */
|
||||||
|
/* Finally, EBP doesn't seem to support truncation metadata. */
|
||||||
|
const EBP_MAGIC_META_OPENER = 0x7B //UTF-8 '{'
|
||||||
|
const EBP_META_DEFAULT={"author": "Unknown", "title": "Untitled", "description": "No description"}
|
||||||
|
|
||||||
if(typeof module !== "undefined" && module.exports){
|
if(typeof module !== "undefined" && module.exports){
|
||||||
module.exports = IPS;
|
module.exports = IPS;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +23,8 @@ if(typeof module !== "undefined" && module.exports){
|
||||||
function IPS(){
|
function IPS(){
|
||||||
this.records=[];
|
this.records=[];
|
||||||
this.truncate=false;
|
this.truncate=false;
|
||||||
|
this.isEBP=false;
|
||||||
|
this.EBPmetadata=JSON.stringify(EBP_META_DEFAULT)
|
||||||
}
|
}
|
||||||
IPS.prototype.addSimpleRecord=function(o, d){
|
IPS.prototype.addSimpleRecord=function(o, d){
|
||||||
this.records.push({offset:o, type:IPS_RECORD_SIMPLE, length:d.length, data:d})
|
this.records.push({offset:o, type:IPS_RECORD_SIMPLE, length:d.length, data:d})
|
||||||
|
@ -21,6 +32,10 @@ IPS.prototype.addSimpleRecord=function(o, d){
|
||||||
IPS.prototype.addRLERecord=function(o, l, b){
|
IPS.prototype.addRLERecord=function(o, l, b){
|
||||||
this.records.push({offset:o, type:IPS_RECORD_RLE, length:l, byte:b})
|
this.records.push({offset:o, type:IPS_RECORD_RLE, length:l, byte:b})
|
||||||
}
|
}
|
||||||
|
IPS.prototype.addEBPMetadata=function(author, title, description){
|
||||||
|
/* currently not used - no frontend support */
|
||||||
|
this.EBPmetadata=JSON.stringify({"author": author, "title": title, "description": description})
|
||||||
|
}
|
||||||
IPS.prototype.toString=function(){
|
IPS.prototype.toString=function(){
|
||||||
nSimpleRecords=0;
|
nSimpleRecords=0;
|
||||||
nRLERecords=0;
|
nRLERecords=0;
|
||||||
|
@ -33,8 +48,9 @@ IPS.prototype.toString=function(){
|
||||||
var s='Simple records: '+nSimpleRecords;
|
var s='Simple records: '+nSimpleRecords;
|
||||||
s+='\nRLE records: '+nRLERecords;
|
s+='\nRLE records: '+nRLERecords;
|
||||||
s+='\nTotal records: '+this.records.length;
|
s+='\nTotal records: '+this.records.length;
|
||||||
if(this.truncate)
|
if(this.truncate && !this.isEBP)
|
||||||
s+='\nTruncate at: 0x'+this.truncate.toString(16);
|
s+='\nTruncate at: 0x'+this.truncate.toString(16);
|
||||||
|
s+='\nIs EBP: '+this.isEBP
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
IPS.prototype.export=function(fileName){
|
IPS.prototype.export=function(fileName){
|
||||||
|
@ -46,11 +62,13 @@ IPS.prototype.export=function(fileName){
|
||||||
patchFileSize+=(3+2+this.records[i].data.length); //offset+length+data
|
patchFileSize+=(3+2+this.records[i].data.length); //offset+length+data
|
||||||
}
|
}
|
||||||
patchFileSize+=3; //EOF string
|
patchFileSize+=3; //EOF string
|
||||||
if(this.truncate)
|
if(this.truncate && !this.isEBP)
|
||||||
patchFileSize+=3; //truncate
|
patchFileSize+=3; //truncate
|
||||||
|
if(this.isEBP)
|
||||||
|
patchFileSize+=this.EBPmetadata.length
|
||||||
|
|
||||||
tempFile=new BinFile(patchFileSize);
|
tempFile=new BinFile(patchFileSize);
|
||||||
tempFile.fileName=fileName+'.ips';
|
tempFile.fileName=fileName+('.ebp' ? this.isEBP : '.ips');
|
||||||
tempFile.writeString(IPS_MAGIC);
|
tempFile.writeString(IPS_MAGIC);
|
||||||
for(var i=0; i<this.records.length; i++){
|
for(var i=0; i<this.records.length; i++){
|
||||||
var rec=this.records[i];
|
var rec=this.records[i];
|
||||||
|
@ -66,14 +84,17 @@ IPS.prototype.export=function(fileName){
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFile.writeString('EOF');
|
tempFile.writeString('EOF');
|
||||||
if(this.truncate)
|
if(this.truncate && !this.isEBP)
|
||||||
tempFile.writeU24(this.truncate);
|
tempFile.writeU24(this.truncate);
|
||||||
|
|
||||||
|
if(this.isEBP) {
|
||||||
|
tempFile.writeString(this.EBPmetadata)
|
||||||
|
}
|
||||||
|
|
||||||
return tempFile
|
return tempFile
|
||||||
}
|
}
|
||||||
IPS.prototype.apply=function(romFile){
|
IPS.prototype.apply=function(romFile){
|
||||||
if(this.truncate){
|
if(this.truncate && !this.isEBP){
|
||||||
if(this.truncate>romFile.fileSize){ //expand (discussed here: https://github.com/marcrobledo/RomPatcher.js/pull/46)
|
if(this.truncate>romFile.fileSize){ //expand (discussed here: https://github.com/marcrobledo/RomPatcher.js/pull/46)
|
||||||
tempFile=new BinFile(this.truncate);
|
tempFile=new BinFile(this.truncate);
|
||||||
romFile.copyTo(tempFile, 0, romFile.fileSize, 0);
|
romFile.copyTo(tempFile, 0, romFile.fileSize, 0);
|
||||||
|
@ -136,6 +157,8 @@ IPS.fromFile=function(file){
|
||||||
}else if((file.offset+3)===file.fileSize){
|
}else if((file.offset+3)===file.fileSize){
|
||||||
patchFile.truncate=file.readU24();
|
patchFile.truncate=file.readU24();
|
||||||
break;
|
break;
|
||||||
|
}else if (file.readU8()===EBP_MAGIC_META_OPENER) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,10 +174,12 @@ IPS.fromFile=function(file){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IPS.buildFromRoms=function(original, modified){
|
IPS.buildFromRoms=function(original, modified, asEBP=false){
|
||||||
var patch=new IPS();
|
var patch=new IPS();
|
||||||
|
|
||||||
if(modified.fileSize<original.fileSize){
|
patch.isEBP=asEBP
|
||||||
|
|
||||||
|
if(modified.fileSize<original.fileSize && !patch.isEBP){
|
||||||
patch.truncate=modified.fileSize;
|
patch.truncate=modified.fileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +229,7 @@ IPS.buildFromRoms=function(original, modified){
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(startOffset>=IPS_MAX_ROM_SIZE){
|
if(startOffset>=IPS_MAX_ROM_SIZE){
|
||||||
throw new Error('Files are too big for IPS format');
|
throw new Error(`Files are too big for ${'EBP' ? patch.isEBP : 'IPS'} format`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
test.js
11
test.js
|
@ -14,6 +14,9 @@
|
||||||
- IPS test
|
- IPS test
|
||||||
- Patch: https://www.romhacking.net/hacks/3784/
|
- Patch: https://www.romhacking.net/hacks/3784/
|
||||||
- ROM: Super Mario Land 2 - 6 Golden Coins (USA, Europe).gb [CRC32=d5ec24e4]
|
- ROM: Super Mario Land 2 - 6 Golden Coins (USA, Europe).gb [CRC32=d5ec24e4]
|
||||||
|
- EBP test
|
||||||
|
- Patch: https://forum.starmen.net/forum/Community/PKHack/NickBound/page/1#post2333521
|
||||||
|
- ROM: EarthBound (USA).sfc [CRC32=dc9bb451]
|
||||||
- BPS test
|
- BPS test
|
||||||
- Patch: https://www.romhacking.net/translations/6297/
|
- Patch: https://www.romhacking.net/translations/6297/
|
||||||
- ROM: Samurai Kid (Japan).gbc [CRC32=44a9ddfb]
|
- ROM: Samurai Kid (Japan).gbc [CRC32=44a9ddfb]
|
||||||
|
@ -50,6 +53,14 @@ const TEST_PATCHES = [
|
||||||
patchCrc32: 0x0b742316,
|
patchCrc32: 0x0b742316,
|
||||||
patchDownload: 'https://www.romhacking.net/hacks/3784/',
|
patchDownload: 'https://www.romhacking.net/hacks/3784/',
|
||||||
outputCrc32: 0xf0799017
|
outputCrc32: 0xf0799017
|
||||||
|
}, {
|
||||||
|
title: 'EBP - Mother Rebound',
|
||||||
|
romFile: 'EarthBound (USA).sfc',
|
||||||
|
romCrc32: 0xdc9bb451,
|
||||||
|
patchFile: 'Mother_Rebound.ebp',
|
||||||
|
patchCrc32: 0x271719e1,
|
||||||
|
patchDownload: 'https://forum.starmen.net/forum/Community/PKHack/NickBound/page/1#post2333521',
|
||||||
|
outputCrc32: 0x5065b02f
|
||||||
}, {
|
}, {
|
||||||
title: 'BPS - Samurai Kid translation',
|
title: 'BPS - Samurai Kid translation',
|
||||||
romFile: 'Samurai Kid (Japan).gbc',
|
romFile: 'Samurai Kid (Japan).gbc',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue