/* UPS module for RomPatcher.js v20180428 - Marc Robledo 2017-2018 - http://www.marcrobledo.com/license */ /* File format specification: http://www.romhacking.net/documents/392/ */ var UPS_MAGIC='UPS1'; function UPS(){ this.records=[]; this.sizeInput=0; this.sizeOutput=0; this.checksumInput=0; this.checksumOutput=0; } UPS.prototype.addRecord=function(o, d){ this.records.push({offset:o, XORdata:d}) } UPS.prototype.toString=function(){ var s='Records: '+this.records.length; s+='\nInput file size: '+this.sizeInput; s+='\nOutput file size: '+this.sizeOutput; s+='\nInput file checksum: '+this.checksumInput; s+='\nOutput file checksum: '+this.checksumOutput; return s } UPS.prototype.export=function(fileName){ var encodedSizeInput=encodeVLV(this.sizeInput); var encodedSizeOutput=encodeVLV(this.sizeOutput); var encodedRecords=[]; var binFileSize=0; binFileSize+=UPS_MAGIC.length; //UPS1 string binFileSize+=encodedSizeInput.length; //input file size binFileSize+=encodedSizeOutput.length; //output file size for(var i=0; i>7; if(offset===0){ bytes.push(0x80 | x); break; } bytes.push(x); offset=offset-1; } return bytes; } function decodeVLV(file, pos){ var offset=0; var size=0; var shift=1; while(1){ var x=file.readByte(pos); pos++; if(x==-1) console.error('corrupted UPS file?'); size++; offset+=(x&0x7f)*shift; if((x&0x80)!==0) break; shift=shift<<7; offset+=shift; } return {offset:offset, size:size} } function readUPSFile(file){ var patchFile=new UPS(); var decodedInputFilesize=decodeVLV(tempFile,4); patchFile.sizeInput=decodedInputFilesize.offset; var decodedOutputFilesize=decodeVLV(tempFile,4+decodedInputFilesize.size); patchFile.sizeOutput=decodedOutputFilesize.offset; var seek=4+decodedInputFilesize.size+decodedOutputFilesize.size; var nextOffset=0; while(seek<(tempFile.fileSize-12)){ var decodedOffset=decodeVLV(tempFile, seek); seek+=decodedOffset.size; nextOffset+=decodedOffset.offset; var bytes=[]; var lastByte; while(lastByte=tempFile.readByte(seek)){ bytes.push(lastByte); seek++; } seek++; patchFile.addRecord(decodedOffset.offset, bytes); } file.littleEndian=true; patchFile.checksumInput=tempFile.readInt(seek); patchFile.checksumOutput=tempFile.readInt(seek+4); if(tempFile.readInt(seek+8)!==crc32(file, true)){ MarcDialogs.alert('Warning: invalid patch checksum'); } return patchFile; } function createUPSFromFiles(original, modified){ tempFile=new UPS(); tempFile.sizeInput=original.fileSize; tempFile.sizeOutput=modified.fileSize; var seek=0; var previousSeek=0; while(seek=original.fileSize?0x00:original.readByte(seek); var b2=modified.readByte(seek); if(b1!==b2){ var currentSeek=seek; var differentBytes=[]; while(b1!==b2){ differentBytes.push(b1 ^ b2); seek++; if(seek===modified.fileSize) break; b1=seek>=original.fileSize?0x00:original.readByte(seek); b2=modified.readByte(seek); } var nextDifference=currentSeek-previousSeek; tempFile.addRecord(nextDifference, differentBytes); previousSeek=currentSeek+differentBytes.length+1; seek++; }else{ seek++; } } tempFile.checksumInput=crc32(original); tempFile.checksumOutput=crc32(modified); return tempFile }