/* ips-patcher.js v20170722 - Marc Robledo 2016-2017 - http://www.marcrobledo.com/license */
var MAX_ROM_SIZE=33554432;
var romFile, patch, romFile1, romFile2, tempFile, romHashes={};
/* Shortcuts */
function addEvent(e,ev,f){e.addEventListener(ev,f,false)}
function el(e){return document.getElementById(e)}
/* initialize app */
addEvent(window,'load',function(){
el('input-file-rom').value='';
el('input-file-patch').value='';
el('input-file-rom1').value='';
el('input-file-rom2').value='';
el('input-file-flip').value='';
addEvent(el('input-file-rom'), 'change', function(){
romFile=new MarcBinFile(this, function(){
el('rom-info').innerHTML='';
sha1(romFile);
romHashes.crc32=crc32(romFile);
romHashes.md5=md5(romFile);
var crc32str=romHashes.crc32.toString(16);
while(crc32str.length<8)
crc32str='0'+crc32str;
el('rom-info').innerHTML+='CRC32: '+crc32str+'
';
el('rom-info').innerHTML+='MD5: '+romHashes.md5+'
';
});
});
addEvent(el('input-file-patch'), 'change', function(){
openPatchFile(this);
});
addEvent(el('input-file-rom1'), 'change', function(){
romFile1=new MarcBinFile(this);
});
addEvent(el('input-file-rom2'), 'change', function(){
romFile2=new MarcBinFile(this);
});
});
function _readPatchFile(){
tempFile.littleEndian=false;
if(tempFile.readString(0,5)===IPS_MAGIC){
patch=readIPSFile(tempFile);
}else if(tempFile.readString(0,4)===UPS_MAGIC){
patch=readUPSFile(tempFile);
}else{
MarcDialogs.alert('Invalid IPS/UPS file');
}
}
function openPatchFile(f){tempFile=new MarcBinFile(f, _readPatchFile)}
function applyPatchFile(p,r){
if(p && r){
var patchedROM=p.apply(r);
patchedROM.fileName=r.fileName.replace(/\.(.*?)$/, ' (patched).$1');
patchedROM.save()
}else{
MarcDialogs.alert('No ROM/patch selected');
}
}
function createPatchFile(){
var MODES=['ips','ups'];
var mode=0;
for(var i=0; iMAX_IPS_SIZE || romFile2.fileSize>MAX_IPS_SIZE)){
MarcDialogs.alert('Files are too big for IPS format');
return false;
}
var newPatch;
if(mode==='ips'){
newPatch=createIPSFromFiles(romFile1, romFile2);
}else if(mode==='ups'){
newPatch=createUPSFromFiles(romFile1, romFile2);
}
newPatch.export().save();
}
/* CRC32/MD5/SHA-1 calculators */
var HEX_CHR='0123456789abcdef'.split('');
var CRC_TABLE=false;
var CAN_USE_CRYPTO_API=(window.crypto&&window.crypto.subtle&&window.crypto.subtle.digest);
/* SHA-1 using WebCryptoAPI */
function sha1(file){
if(CAN_USE_CRYPTO_API && file.fileSize<=MAX_ROM_SIZE){
window.crypto.subtle.digest('SHA-1', file.fileReader.dataView.buffer).then(function(hash){
//console.log('SHA-1:'+);
var bytes=new Uint8Array(hash);
var hexString='';
for(var i=0;i';
}).catch(function(error){
console.error(error);
});
}
}
/* MD5 - from Joseph's Myers - http://www.myersdaily.org/joseph/javascript/md5.js */
function _add32(a,b){return (a+b)&0xffffffff}
function _md5cycle(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a=ff(a,b,c,d,k[0],7,-680876936);d=ff(d,a,b,c,k[1],12,-389564586);c=ff(c,d,a,b,k[2],17,606105819);b=ff(b,c,d,a,k[3],22,-1044525330);a=ff(a,b,c,d,k[4],7,-176418897);d=ff(d,a,b,c,k[5],12,1200080426);c=ff(c,d,a,b,k[6],17,-1473231341);b=ff(b,c,d,a,k[7],22,-45705983);a=ff(a,b,c,d,k[8],7,1770035416);d=ff(d,a,b,c,k[9],12,-1958414417);c=ff(c,d,a,b,k[10],17,-42063);b=ff(b,c,d,a,k[11],22,-1990404162);a=ff(a,b,c,d,k[12],7,1804603682);d=ff(d,a,b,c,k[13],12,-40341101);c=ff(c,d,a,b,k[14],17,-1502002290);b=ff(b,c,d,a,k[15],22,1236535329);a=gg(a,b,c,d,k[1],5,-165796510);d=gg(d,a,b,c,k[6],9,-1069501632);c=gg(c,d,a,b,k[11],14,643717713);b=gg(b,c,d,a,k[0],20,-373897302);a=gg(a,b,c,d,k[5],5,-701558691);d=gg(d,a,b,c,k[10],9,38016083);c=gg(c,d,a,b,k[15],14,-660478335);b=gg(b,c,d,a,k[4],20,-405537848);a=gg(a,b,c,d,k[9],5,568446438);d=gg(d,a,b,c,k[14],9,-1019803690);c=gg(c,d,a,b,k[3],14,-187363961);b=gg(b,c,d,a,k[8],20,1163531501);a=gg(a,b,c,d,k[13],5,-1444681467);d=gg(d,a,b,c,k[2],9,-51403784);c=gg(c,d,a,b,k[7],14,1735328473);b=gg(b,c,d,a,k[12],20,-1926607734);a=hh(a,b,c,d,k[5],4,-378558);d=hh(d,a,b,c,k[8],11,-2022574463);c=hh(c,d,a,b,k[11],16,1839030562);b=hh(b,c,d,a,k[14],23,-35309556);a=hh(a,b,c,d,k[1],4,-1530992060);d=hh(d,a,b,c,k[4],11,1272893353);c=hh(c,d,a,b,k[7],16,-155497632);b=hh(b,c,d,a,k[10],23,-1094730640);a=hh(a,b,c,d,k[13],4,681279174);d=hh(d,a,b,c,k[0],11,-358537222);c=hh(c,d,a,b,k[3],16,-722521979);b=hh(b,c,d,a,k[6],23,76029189);a=hh(a,b,c,d,k[9],4,-640364487);d=hh(d,a,b,c,k[12],11,-421815835);c=hh(c,d,a,b,k[15],16,530742520);b=hh(b,c,d,a,k[2],23,-995338651);a=ii(a,b,c,d,k[0],6,-198630844);d=ii(d,a,b,c,k[7],10,1126891415);c=ii(c,d,a,b,k[14],15,-1416354905);b=ii(b,c,d,a,k[5],21,-57434055);a=ii(a,b,c,d,k[12],6,1700485571);d=ii(d,a,b,c,k[3],10,-1894986606);c=ii(c,d,a,b,k[10],15,-1051523);b=ii(b,c,d,a,k[1],21,-2054922799);a=ii(a,b,c,d,k[8],6,1873313359);d=ii(d,a,b,c,k[15],10,-30611744);c=ii(c,d,a,b,k[6],15,-1560198380);b=ii(b,c,d,a,k[13],21,1309151649);a=ii(a,b,c,d,k[4],6,-145523070);d=ii(d,a,b,c,k[11],10,-1120210379);c=ii(c,d,a,b,k[2],15,718787259);b=ii(b,c,d,a,k[9],21,-343485551);x[0]=_add32(a,x[0]);x[1]=_add32(b,x[1]);x[2]=_add32(c,x[2]);x[3]=_add32(d,x[3])}
function _md5blk(d){var md5blks=[],i;for(i=0;i<64;i+=4)md5blks[i>>2]=d[i]+(d[i+1]<<8)+(d[i+2]<<16)+(d[i+3]<<24);return md5blks}
function _cmn(q,a,b,x,s,t){a=_add32(_add32(a,q),_add32(x,t));return _add32((a<>>(32-s)),b)}
function ff(a,b,c,d,x,s,t){return _cmn((b&c)|((~b)&d),a,b,x,s,t)}
function gg(a,b,c,d,x,s,t){return _cmn((b&d)|(c&(~d)),a,b,x,s,t)}
function hh(a,b,c,d,x,s,t){return _cmn(b^c^d,a,b,x,s,t)}
function ii(a,b,c,d,x,s,t){return _cmn(c^(b|(~d)),a,b,x,s,t)}
function md5(file){
var data=new Uint8Array(file.fileReader.dataView.buffer);
var n=data.length,state=[1732584193,-271733879,-1732584194,271733878],i;
for(i=64;i<=data.length;i+=64)
_md5cycle(state,_md5blk(data.slice(i-64,i)));
data=data.slice(i-64);
var tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
for(i=0;i>2]|=data[i]<<((i%4)<<3);
tail[i>>2]|=0x80<<((i%4)<<3);
if(i>55){
_md5cycle(state,tail);
for(i=0;i<16;i++)tail[i]=0;
}
tail[14]=n*8;
_md5cycle(state,tail);
for(var i=0;i>(j*8+4))&0x0f]+HEX_CHR[(state[i]>>(j*8))&0x0f];
state[i]=s;
}
return state.join('')
}
/* CRC32 - from Alex - https://stackoverflow.com/a/18639999 */
function _makeCRCTable(){
var c,crcTable=[];
for(var n=0;n<256;n++){
c=n;
for(var k=0;k<8;k++)
c=((c&1)?(0xedb88320^(c>>>1)):(c>>>1));
crcTable[n]=c;
}
return crcTable;
}
function crc32(file,ignoreLast4Bytes){
var data=new Uint8Array(file.fileReader.dataView.buffer);
if(!CRC_TABLE)
CRC_TABLE=_makeCRCTable();
var crc=0^(-1);
var len=ignoreLast4Bytes?data.length-4:data.length;
for(var i=0;i>>8)^CRC_TABLE[(crc^data[i])&0xff];
return ((crc^(-1))>>>0);
}
/* MarcDialogs.js */
MarcDialogs=function(){function e(e,t,n){a?e.attachEvent("on"+t,n):e.addEventListener(t,n,!1)}function t(){s&&(o?history.go(-1):(c.className="dialog-overlay",s.className=s.className.replace(/ active/g,""),s=null))}function n(e){for(var t=0;t0;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> 16, (val & 0x00ff00) >> 8, (val & 0x0000ff)])}
/* FileSaver.min.js: https://github.com/eligrey/FileSaver.js/blob/master/FileSaver.min.js */
var saveAs=saveAs||function(view){"use strict";if(typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var doc=view.document,get_URL=function(){return view.URL||view.webkitURL||view},save_link=doc.createElementNS("http://www.w3.org/1999/xhtml","a"),can_use_save_link="download"in save_link,click=function(node){var event=new MouseEvent("click");node.dispatchEvent(event)},is_safari=/Version\/[\d\.]+.*Safari/.test(navigator.userAgent),webkit_req_fs=view.webkitRequestFileSystem,req_fs=view.requestFileSystem||webkit_req_fs||view.mozRequestFileSystem,throw_outside=function(ex){(view.setImmediate||view.setTimeout)(function(){throw ex},0)},force_saveable_type="application/octet-stream",fs_min_size=0,arbitrary_revoke_timeout=500,revoke=function(file){var revoker=function(){if(typeof file==="string"){get_URL().revokeObjectURL(file)}else{file.remove()}};if(view.chrome){revoker()}else{setTimeout(revoker,arbitrary_revoke_timeout)}},dispatch=function(filesaver,event_types,event){event_types=[].concat(event_types);var i=event_types.length;while(i--){var listener=filesaver["on"+event_types[i]];if(typeof listener==="function"){try{listener.call(filesaver,event||filesaver)}catch(ex){throw_outside(ex)}}}},auto_bom=function(blob){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)){return new Blob(["\ufeff",blob],{type:blob.type})}return blob},FileSaver=function(blob,name,no_auto_bom){if(!no_auto_bom){blob=auto_bom(blob)}var filesaver=this,type=blob.type,blob_changed=false,object_url,target_view,dispatch_all=function(){dispatch(filesaver,"writestart progress write writeend".split(" "))},fs_error=function(){if(target_view&&is_safari&&typeof FileReader!=="undefined"){var reader=new FileReader;reader.onloadend=function(){var base64Data=reader.result;target_view.location.href="data:attachment/file"+base64Data.slice(base64Data.search(/[,;]/));filesaver.readyState=filesaver.DONE;dispatch_all()};reader.readAsDataURL(blob);filesaver.readyState=filesaver.INIT;return}if(blob_changed||!object_url){object_url=get_URL().createObjectURL(blob)}if(target_view){target_view.location.href=object_url}else{var new_tab=view.open(object_url,"_blank");if(new_tab==undefined&&is_safari){view.location.href=object_url}}filesaver.readyState=filesaver.DONE;dispatch_all();revoke(object_url)},abortable=function(func){return function(){if(filesaver.readyState!==filesaver.DONE){return func.apply(this,arguments)}}},create_if_not_found={create:true,exclusive:false},slice;filesaver.readyState=filesaver.INIT;if(!name){name="download"}if(can_use_save_link){object_url=get_URL().createObjectURL(blob);setTimeout(function(){save_link.href=object_url;save_link.download=name;click(save_link);dispatch_all();revoke(object_url);filesaver.readyState=filesaver.DONE});return}if(view.chrome&&type&&type!==force_saveable_type){slice=blob.slice||blob.webkitSlice;blob=slice.call(blob,0,blob.size,force_saveable_type);blob_changed=true}if(webkit_req_fs&&name!=="download"){name+=".download"}if(type===force_saveable_type||webkit_req_fs){target_view=view}if(!req_fs){fs_error();return}fs_min_size+=blob.size;req_fs(view.TEMPORARY,fs_min_size,abortable(function(fs){fs.root.getDirectory("saved",create_if_not_found,abortable(function(dir){var save=function(){dir.getFile(name,create_if_not_found,abortable(function(file){file.createWriter(abortable(function(writer){writer.onwriteend=function(event){target_view.location.href=file.toURL();filesaver.readyState=filesaver.DONE;dispatch(filesaver,"writeend",event);revoke(file)};writer.onerror=function(){var error=writer.error;if(error.code!==error.ABORT_ERR){fs_error()}};"writestart progress write abort".split(" ").forEach(function(event){writer["on"+event]=filesaver["on"+event]});writer.write(blob);filesaver.abort=function(){writer.abort();filesaver.readyState=filesaver.DONE};filesaver.readyState=filesaver.WRITING}),fs_error)}),fs_error)};dir.getFile(name,{create:false},abortable(function(file){file.remove();save()}),abortable(function(ex){if(ex.code===ex.NOT_FOUND_ERR){save()}else{fs_error()}}))}),fs_error)}),fs_error)},FS_proto=FileSaver.prototype,saveAs=function(blob,name,no_auto_bom){return new FileSaver(blob,name,no_auto_bom)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(blob,name,no_auto_bom){if(!no_auto_bom){blob=auto_bom(blob)}return navigator.msSaveOrOpenBlob(blob,name||"download")}}FS_proto.abort=function(){var filesaver=this;filesaver.readyState=filesaver.DONE;dispatch(filesaver,"abort")};FS_proto.readyState=FS_proto.INIT=0;FS_proto.WRITING=1;FS_proto.DONE=2;FS_proto.error=FS_proto.onwritestart=FS_proto.onprogress=FS_proto.onwrite=FS_proto.onabort=FS_proto.onerror=FS_proto.onwriteend=null;return saveAs}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!=null){define([],function(){return saveAs})}