/* RUP module for Rom Patcher JS v20250430 - Marc Robledo 2018-2025 - http://www.marcrobledo.com/license */ /* File format specification: http://www.romhacking.net/documents/288/ */ const RUP_MAGIC='NINJA2'; const RUP_COMMAND_END=0x00; const RUP_COMMAND_OPEN_NEW_FILE=0x01; const RUP_COMMAND_XOR_RECORD=0x02; const RUP_ROM_TYPES=['raw','nes','fds','snes','n64','gb','sms','mega','pce','lynx']; if(typeof module !== "undefined" && module.exports){ module.exports = RUP; } function RUP(){ this.author=''; this.version=''; this.title=''; this.genre=''; this.language=''; this.date=''; this.web=''; this.description=''; this.files=[]; } RUP.prototype.toString=function(){ var s='Author: '+this.author; s+='\nVersion: '+this.version; s+='\nTitle: '+this.title; s+='\nGenre: '+this.genre; s+='\nLanguage: '+this.language; s+='\nDate: '+this.date; s+='\nWeb: '+this.web; s+='\nDescription: '+this.description; for(var i=0; i byte ^ 0xff)); }else if(patch.overflowMode==='M' && undo){ /* minify */ tempFile.seek(patch.targetFileSize); tempFile.writeBytes(patch.overflowData.map((byte) => byte ^ 0xff)); } if( validate && ( (!undo && tempFile.hashMD5()!==patch.targetMD5) || (undo && tempFile.hashMD5()!==patch.sourceMD5) ) ){ throw new Error('Target ROM checksum mismatch'); } if(undo) tempFile.unpatched=true; return tempFile } RUP.MAGIC=RUP_MAGIC; RUP.padZeroes=function(intVal, nBytes){ var hexString=intVal.toString(16); while(hexString.lengthtarget) or 'A' (source>=8; } } function RUP_getVLVLen(data){ var ret=1; while(data){ ret++; data>>=8; } return ret; } RUP.prototype.export=function(fileName){ var patchFileSize=2048; for(var i=0; ifile.targetFileSize?'M':'A'); patchFile.writeVLV(file.overflowData.length); patchFile.writeBytes(file.overflowData); } for(var j=0; j byte ^ 0xff); modified=modified.slice(0, file.sourceFileSize); }else if(file.sourceFileSize>file.targetFileSize){ original.seek(file.targetFileSize); file.overflowMode='M'; file.overflowData=original.readBytes(file.sourceFileSize-file.targetFileSize).map((byte) => byte ^ 0xff); original=original.slice(0, file.targetFileSize); } original.seek(0); modified.seek(0); while(!modified.isEOF()){ var b1=original.isEOF()?0x00:original.readU8(); var b2=modified.readU8(); if(b1!==b2){ var originalOffset=modified.offset-1; var xorDifferences=[]; while(b1!==b2){ xorDifferences.push(b1^b2); if(modified.isEOF()) break; b1=original.isEOF()?0x00:original.readU8(); b2=modified.readU8(); } file.records.push({offset:originalOffset, xor:xorDifferences}); } } patch.files.push(file); return patch }