diff --git a/index.html b/index.html new file mode 100644 index 0000000..033bea9 --- /dev/null +++ b/index.html @@ -0,0 +1,91 @@ + + + + IPS Patcher + + + + + + + + + + + + + + + + +
+
+ This small web app allows you to apply a IPS patch to your favorite retro games. +
+ + + + + +
+

Apply IPS patch

+
+
+
+ +
+
+ +
+
+
+ +
+
+ +
+ +
+ +
+ + + + + +
+

Create IPS patch

+
+
+
+ +
+
+ +
+
+
+ +
+
+ +
+ +
+ +
+
+ + + + + \ No newline at end of file diff --git a/ips-patcher.appcache b/ips-patcher.appcache new file mode 100644 index 0000000..bd20b70 --- /dev/null +++ b/ips-patcher.appcache @@ -0,0 +1,6 @@ +CACHE MANIFEST +# last update 2017-02-28 +# these belong to the CACHE block +index.html +ips-patcher.js +ips-patcher.png \ No newline at end of file diff --git a/ips-patcher.js b/ips-patcher.js new file mode 100644 index 0000000..20e0a7c --- /dev/null +++ b/ips-patcher.js @@ -0,0 +1,290 @@ +/* ips-patcher.js v20160416 - Marc Robledo 2016 - http://www.marcrobledo.com/license */ + + + + +/* Implement 3-byte reader/writer in MarcBinFile */ +MarcBinFile.prototype.readThreeBytes=function(offset){ + return (this.readByte(offset+0) << 16)+(this.readByte(offset+1) << 8)+(this.readByte(offset+2)) +} +MarcBinFile.prototype.writeThreeBytes=function(offset,val){ + this.writeBytes(offset, [(val & 0xff0000) >> 16, (val & 0x00ff00) >> 8, (val & 0x0000ff)]); +} + + + + + + +/* Shortcuts */ +function addEvent(e,ev,f){e.addEventListener(ev,f,false)} +function el(e){return document.getElementById(e)} + + + + + +/* + IPS file format + doc: http://www.smwiki.net/wiki/IPS_file_format +*/ +var RECORD_RLE=0x0000; +var RECORD_SIMPLE=1; +function IPS(){ + this.records=[]; + this.truncate=false; +} +IPS.prototype.addSimpleRecord=function(o, d){ + this.records.push({offset:o, type:RECORD_SIMPLE, data:d}) +} +IPS.prototype.addRLERecord=function(o, l, b){ + this.records.push({offset:o, type:RECORD_RLE, length:l, byte:b}) +} +IPS.prototype.toString=function(){ + nSimpleRecords=0; + nRLERecords=0; + for(var i=0; iromFile.fileSize){ + alert('Invalid ROM file (too big?).'); + return false; + } + }else{ + if(rec.offset+rec.data.length>romFile.fileSize){ + alert('Invalid ROM file (too big?).'); + return false; + } + } + } + + var patchedFile=new MarcBinFile(romFile.fileSize); + patchedFile.fileName=romFile.fileName.replace(/\.(.*?)$/, ' (patched).$1'); + var clonedFileSize=this.truncate || romFile.fileSize; + for(var i=0; i16777215) + alert('Too big ROM file'); + }); +} + +function openROM1(f){ + romFile1=new MarcBinFile(f, function(){ + if(romFile1.fileSize>16777215) + alert('Too big ROM file'); + }); +} +function openROM2(f){ + romFile2=new MarcBinFile(f, function(){ + if(romFile2.fileSize>16777215) + alert('Too big ROM file'); + }); +} + +function openIPS(f){ + tempFile=new MarcBinFile(f, readIPS); +} + + + + + + +function readIPS(){ + tempFile.littleEndian=false; + + if(tempFile.readString(0,5)!=='PATCH'){ + MarcDialogs.alert('Invalid IPS File'); + return false; + } + + + ipsFile=new IPS(); + var EOF=false; + var seek=5; + + while(seekmodified.fileSize){ + seekStart--; + } + for(var i=seekStart;i>0 && nearbyDifference;i--){ + var bc1=original.readByte(seek+i); + var bc2=modified.readByte(seek+i); + + if(bc1!=bc2){ + length+=i; + seek+=i; + break; + }else if(i==1){ + nearbyDifference=false; + } + } + } + + var data=modified.readBytes(originalSeek, length); + /* check RLE record */ + for(var i=1; i0;e++)d+=String.fromCharCode(c[e]);return d},MarcBinFile.prototype.writeByte=function(a,b){this.fileReader.dataView.setUint8(a,b,this.littleEndian)},MarcBinFile.prototype.writeByteSigned=function(a,b){this.fileReader.dataView.setInt8(a,b,this.littleEndian)},MarcBinFile.prototype.writeBytes=function(a,b){for(var c=0;c