diff --git a/RomPatcher.js b/RomPatcher.js index b30d73e..3d47f90 100644 --- a/RomPatcher.js +++ b/RomPatcher.js @@ -1,4 +1,4 @@ -/* ips-patcher.js v20170722 - Marc Robledo 2016-2017 - http://www.marcrobledo.com/license */ +/* RomPatcher.js v20171102 - Marc Robledo 2016-2017 - http://www.marcrobledo.com/license */ var MAX_ROM_SIZE=33554432; var romFile, patch, romFile1, romFile2, tempFile, romHashes={}; /* Shortcuts */ @@ -54,10 +54,12 @@ function _readPatchFile(){ patch=readUPSFile(tempFile); }else if(tempFile.readString(0,5)===APS_MAGIC){ patch=readAPSFile(tempFile); + }else if(tempFile.readString(0,4)===BPS_MAGIC){ + patch=readBPSFile(tempFile); }/*else if(tempFile.readString(0,4)===APSGBA_MAGIC){ patch=readAPSGBAFile(tempFile); }*/else { - MarcDialogs.alert('Invalid IPS/UPS/APS file'); + MarcDialogs.alert('Invalid IPS/UPS/APS/BPS file'); } } function openPatchFile(f){tempFile=new MarcBinFile(f, _readPatchFile)} @@ -74,7 +76,7 @@ function applyPatchFile(p,r){ function createPatchFile(){ - var MODES=['ips','ups','aps','apsn64'/*,'apsgba'*/]; + var MODES=['ips','ups','aps','apsn64'/*,'apsgba','bps'*/]; var mode=0; for(var i=0; i> 2)+1}; + seek+=data.length; + + newFileSize+=action.length; + if(action.type===BPS_ACTION_TARGET_READ){ + seek+=action.length; + }else if(action.type===BPS_ACTION_SOURCE_COPY || action.type===BPS_ACTION_TARGET_COPY){ + seek+=decodeBPS(this.file, seek).length; + } + } + tempFile=new MarcBinFile(newFileSize); + + + //patch + var outputOffset=0; + var sourceRelativeOffset=0; + var targetRelativeOffset=0; + seek=this.actionsOffset; + while(seek<(this.file.fileSize-12)){ + var data=decodeBPS(this.file, seek); + var action={type: data.number & 3, length: (data.number >> 2)+1}; + //console.log('0x'+seek.toString(16)+' - action: '+action.type+':'+action.length); + seek+=data.length; + + if(action.type===BPS_ACTION_SOURCE_READ){ + tempFile.writeBytes(outputOffset, romFile.readBytes(outputOffset, action.length)); + outputOffset+=action.length; + + }else if(action.type===BPS_ACTION_TARGET_READ){ + tempFile.writeBytes(outputOffset, this.file.readBytes(seek, action.length)); + outputOffset+=action.length; + seek+=action.length; + + }else if(action.type===BPS_ACTION_SOURCE_COPY){ + var data2=decodeBPS(this.file, seek); + seek+=data2.length; + sourceRelativeOffset+=(data2.number & 1 ? -1 : +1) * (data2.number >> 1); + while(action.length--){ + tempFile.writeByte(outputOffset, romFile.readByte(sourceRelativeOffset)); + outputOffset++; + sourceRelativeOffset++; + } + }else if(action.type===BPS_ACTION_TARGET_COPY){ + var data2=decodeBPS(this.file, seek); + seek+=data2.length; + targetRelativeOffset += (data2.number & 1 ? -1 : +1) * (data2.number >> 1); + while(action.length--) { + tempFile.writeByte(outputOffset, tempFile.readByte(targetRelativeOffset)); + outputOffset++; + targetRelativeOffset++; + } + } + } + + if(this.targetChecksum!==crc32(tempFile,false)){ + MarcDialogs.alert('Warning: invalid target ROM checksum'); + } + + return tempFile +} + + + +function readBPSFile(file){ + file.littleEndian=true; + var patchFile=new BPS(); + + var seek=4; //skip BPS1 + var decodedSourceSize=decodeBPS(file, seek); + patchFile.sourceSize=decodedSourceSize.number; + seek+=decodedSourceSize.length; + var decodedTargetSize=decodeBPS(file, seek); + patchFile.targetSize=decodedTargetSize.number; + seek+=decodedTargetSize.length; + + var decodedMetaDataLength=decodeBPS(file, seek); + seek+=decodedMetaDataLength.length; + patchFile.metaData=file.readString(seek, decodedMetaDataLength.length); + seek+=patchFile.metaData.length; + + patchFile.actionsOffset=seek; + patchFile.file=file; + + patchFile.sourceChecksum=file.readInt(file.fileSize-12); + patchFile.targetChecksum=file.readInt(file.fileSize-8); + patchFile.patchChecksum=file.readInt(file.fileSize-4); + + if(patchFile.patchChecksum!==crc32(file,true)){ + MarcDialogs.alert('Warning: invalid patch checksum'); + } + + + return patchFile; +} + + +/*function createBPSFromFiles(original, modified){ + +}*/ + + +/*function encodeBPS(number){ + number=number>>>0; + var dataBytes=[]; + while(true){ + var x = number & 0x7f; + number >>= 7; + if(number == 0){ + dataBytes.push(0x80 | x); + break; + } + dataBytes.push(x); + number--; + } + return dataBytes; +}*/ +function decodeBPS(dataBytes, i){ + var number = 0, shift = 1; + var len=0; + while(true){ + var x = dataBytes.readByte(i); + i++; + len++; + number += (x & 0x7f) * shift; + if(x & 0x80) + break; + shift <<= 7; + number += shift; + } + return {number:number,length:len}; +} \ No newline at end of file diff --git a/index.html b/index.html index b7c3399..c882ef6 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,8 @@ + + @@ -35,7 +37,7 @@

Apply patch

-
Apply an IPS/UPS patch to your ROM
+
Apply a patch to your ROM
@@ -46,7 +48,7 @@
-
+
@@ -60,7 +62,7 @@

Create patch

-
Create an IPS/UPS/APS patch from two different ROMs
+
Create a patch from two different ROMs
@@ -83,6 +85,7 @@ +
@@ -94,7 +97,7 @@

Byte flipper

-
This tool can flip bytes on a file in order to change its endianness
+
This tool flips bytes in a file in order to change its endianness
diff --git a/ips-patcher.appcache b/ips-patcher.appcache deleted file mode 100644 index be07f02..0000000 --- a/ips-patcher.appcache +++ /dev/null @@ -1,17 +0,0 @@ -CACHE MANIFEST -#v20170723 -# WARNING: THIS FILE WILL BE DEPRECATED -#CACHE: -index.html -RomPatcher.css -RomPatcher.js -favicon.png -logo.png -ips.js -ups.js -aps.js -ByteFlipper.js - -# force these files to be loaded in network -NETWORK: -* \ No newline at end of file diff --git a/manifest.appcache b/manifest.appcache index 82ea24a..6f76606 100644 --- a/manifest.appcache +++ b/manifest.appcache @@ -1,5 +1,5 @@ CACHE MANIFEST -#v20171021 +#v20171103 #CACHE: index.html RomPatcher.css @@ -9,6 +9,7 @@ logo.png ips.js ups.js aps.js +bps.js ByteFlipper.js # force these files to be loaded in network