1
0
Fork 0
mirror of https://github.com/marcrobledo/RomPatcher.js.git synced 2025-06-27 16:25:54 +00:00

patch creation can now create IPS patches if offsets are below format limit, rearranged files internally

This commit is contained in:
Marc Robledo 2020-05-02 12:10:46 +02:00
parent e5bc46d725
commit 8146f4860a
27 changed files with 190 additions and 171 deletions

View file

@ -29,34 +29,34 @@ caches.keys().then(function(cacheNames){
}); });
var PRECACHE_ID='rom-patcher-js'; var PRECACHE_ID='rom-patcher-js';
var PRECACHE_VERSION='v8'; var PRECACHE_VERSION='v9';
var PRECACHE_URLS=[ var PRECACHE_URLS=[
'/RomPatcher.js/','/RomPatcher.js/index.html', '/RomPatcher.js/','/RomPatcher.js/index.html',
'/RomPatcher.js/manifest.json', '/RomPatcher.js/manifest.json',
'/RomPatcher.js/favicon.png', '/RomPatcher.js/style/favicon.png',
'/RomPatcher.js/logo114.png', '/RomPatcher.js/style/logo114.png',
'/RomPatcher.js/logo144.png', '/RomPatcher.js/style/logo144.png',
'/RomPatcher.js/logo192.png', '/RomPatcher.js/style/logo192.png',
'/RomPatcher.js/RomPatcher.css', '/RomPatcher.js/style/RomPatcher.css',
'/RomPatcher.js/RomPatcher.js', '/RomPatcher.js/js/RomPatcher.js',
'/RomPatcher.js/locale.js', '/RomPatcher.js/js/locale.js',
'/RomPatcher.js/worker_apply.js', '/RomPatcher.js/js/worker_apply.js',
'/RomPatcher.js/worker_create.js', '/RomPatcher.js/js/worker_create.js',
'/RomPatcher.js/worker_crc.js', '/RomPatcher.js/js/worker_crc.js',
'/RomPatcher.js/libs/MarcFile.js', '/RomPatcher.js/js/MarcFile.js',
'/RomPatcher.js/libs/zip.js', '/RomPatcher.js/js/crc.js',
'/RomPatcher.js/libs/z-worker.js', '/RomPatcher.js/js/zip.js/zip.js',
'/RomPatcher.js/libs/inflate.js', '/RomPatcher.js/js/zip.js/z-worker.js',
'/RomPatcher.js/crc.js', '/RomPatcher.js/js/zip.js/inflate.js',
'/RomPatcher.js/zip.js', '/RomPatcher.js/js/formats/zip.js',
'/RomPatcher.js/ips.js', '/RomPatcher.js/js/formats/ips.js',
'/RomPatcher.js/ups.js', '/RomPatcher.js/js/formats/ups.js',
'/RomPatcher.js/aps.js', '/RomPatcher.js/js/formats/aps.js',
'/RomPatcher.js/bps.js', '/RomPatcher.js/js/formats/bps.js',
'/RomPatcher.js/rup.js', '/RomPatcher.js/js/formats/rup.js',
'/RomPatcher.js/ppf.js', '/RomPatcher.js/js/formats/ppf.js',
'/RomPatcher.js/pmsr.js', '/RomPatcher.js/js/formats/pmsr.js',
'/RomPatcher.js/vcdiff.js' '/RomPatcher.js/js/formats/vcdiff.js'
]; ];

View file

@ -7,30 +7,30 @@
<meta name="keywords" content="ips,ups,aps,bps,rup,ninja,ppf,xdelta,patcher,online,html5,web,rom,patch,hack,translation"/> <meta name="keywords" content="ips,ups,aps,bps,rup,ninja,ppf,xdelta,patcher,online,html5,web,rom,patch,hack,translation"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<link rel="manifest" href="./manifest.json"/> <link rel="manifest" href="./manifest.json"/>
<link rel="shortcut icon" href="./favicon.png" type="image/png" sizes="16x16"/> <link rel="shortcut icon" href="./style/favicon.png" type="image/png" sizes="16x16"/>
<link rel="shortcut icon" href="./logo192.png" type="image/png" sizes="192x192"/> <link rel="shortcut icon" href="./style/logo192.png" type="image/png" sizes="192x192"/>
<!-- iOS icons --> <!-- iOS icons -->
<link rel="apple-touch-icon" sizes="57x57" href="./logo114.png" /> <link rel="apple-touch-icon" sizes="57x57" href="./style/logo114.png" />
<link rel="apple-touch-icon" sizes="114x114" href="./logo114.png" /> <link rel="apple-touch-icon" sizes="114x114" href="./style/logo114.png" />
<link rel="apple-touch-icon" sizes="72x72" href="./logo144.png" /> <link rel="apple-touch-icon" sizes="72x72" href="./style/logo144.png" />
<link rel="apple-touch-icon" sizes="144x144" href="./logo144.png" /> <link rel="apple-touch-icon" sizes="144x144" href="./style/logo144.png" />
<link rel="apple-touch-icon" href="./logo192.png" /> <link rel="apple-touch-icon" href="./style/logo192.png" />
<link type="text/css" rel="stylesheet" href="./RomPatcher.css" media="all"/> <link type="text/css" rel="stylesheet" href="./style/RomPatcher.css" media="all"/>
<script type="text/javascript" src="./locale.js"></script> <script type="text/javascript" src="./js/locale.js"></script>
<script type="text/javascript" src="./RomPatcher.js"></script> <script type="text/javascript" src="./js/RomPatcher.js"></script>
<script type="text/javascript" src="./libs/MarcFile.js"></script> <script type="text/javascript" src="./js/MarcFile.js"></script>
<script type="text/javascript" src="./zip.js"></script> <script type="text/javascript" src="./js/crc.js"></script>
<script type="text/javascript" src="./crc.js"></script> <script type="text/javascript" src="./js/formats/zip.js"></script>
<script type="text/javascript" src="./ips.js"></script> <script type="text/javascript" src="./js/formats/ips.js"></script>
<script type="text/javascript" src="./ups.js"></script> <script type="text/javascript" src="./js/formats/ups.js"></script>
<script type="text/javascript" src="./aps.js"></script> <script type="text/javascript" src="./js/formats/aps.js"></script>
<script type="text/javascript" src="./bps.js"></script> <script type="text/javascript" src="./js/formats/bps.js"></script>
<script type="text/javascript" src="./rup.js"></script> <script type="text/javascript" src="./js/formats/rup.js"></script>
<script type="text/javascript" src="./ppf.js"></script> <script type="text/javascript" src="./js/formats/ppf.js"></script>
<script type="text/javascript" src="./pmsr.js"></script> <script type="text/javascript" src="./js/formats/pmsr.js"></script>
<script type="text/javascript" src="./vcdiff.js"></script> <script type="text/javascript" src="./js/formats/vcdiff.js"></script>
<script type="text/javascript" src="./libs/zip.js"></script> <script type="text/javascript" src="./js/zip.js/zip.js"></script>
<script type="text/javascript"><!-- <script type="text/javascript"><!--
/* /*
@ -55,12 +55,36 @@
]; ];
*/ */
--></script> --></script>
<!-- custom code for RHDN -->
<!--
<?php
if(isset($_REQUEST["file"]) && preg_match("/^(hacks|translations)\/\d+$/", $_REQUEST["file"]) && isset($_REQUEST["patch_name"])){
$patch="/download/".$_REQUEST["file"];
if(isset($_REQUEST["patch"])){
$patch.='#'+strip_tags(trim($_REQUEST["patch"]))
}
$patch_name=strip_tags(trim($_REQUEST["patch_name"]));
$crc="";
if(isset($_REQUEST["crc"]) && preg_match("/^[0-9a-fA-F]{8}$/", $_REQUEST["crc"])){
$crc=', crc:0x'.$_REQUEST["crc"];
}
?>
<script type="text/javascript">
var PREDEFINED_PATCHES=[{patch:'<?= strip_tags($patch); ?>', name:'<?= strip_tags($patch_name); ?>'<?= $crc?>}];
</script>
<?php
}
?>
-->
</head> </head>
<body><div id="column"> <body><div id="column">
<!-- HEADER --> <!-- HEADER -->
<header><img src="logo192.png" /><h1>Rom Patcher JS</h1></header> <header><img src="./style/logo192.png" /><h1>Rom Patcher JS</h1></header>
<!-- APP --> <!-- APP -->
<div id="wrapper"> <div id="wrapper">
@ -149,7 +173,7 @@
<!-- FOOTER --> <!-- FOOTER -->
<footer> <footer>
Rom Patcher JS <small>v2.2b</small> by <a href="/">Marc Robledo</a> Rom Patcher JS <small>v2.3</small> by <a href="/">Marc Robledo</a>
<br /> <br />
<i class="icon github"></i> <a href="https://github.com/marcrobledo/RomPatcher.js/" target="_blank">See on GitHub</a> <i class="icon github"></i> <a href="https://github.com/marcrobledo/RomPatcher.js/" target="_blank">See on GitHub</a>
<i class="icon heart"></i> <a href="https://www.paypal.me/marcrobledo/5" target="_blank" rel="nofollow">Donate</a> <i class="icon heart"></i> <a href="https://www.paypal.me/marcrobledo/5" target="_blank" rel="nofollow">Donate</a>

View file

@ -1,4 +1,4 @@
/* Rom Patcher JS v20200303 - Marc Robledo 2016-2020 - http://www.marcrobledo.com/license */ /* Rom Patcher JS v20200502 - Marc Robledo 2016-2020 - http://www.marcrobledo.com/license */
const TOO_BIG_ROM_SIZE=67108863; const TOO_BIG_ROM_SIZE=67108863;
const HEADERS_INFO=[ const HEADERS_INFO=[
@ -27,31 +27,33 @@ var userLanguage;
var CAN_USE_WEB_WORKERS=true; var CAN_USE_WEB_WORKERS=true;
var webWorkerApply,webWorkerCreate,webWorkerCrc; var webWorkerApply,webWorkerCreate,webWorkerCrc;
try{ try{
webWorkerApply=new Worker('./worker_apply.js'); webWorkerApply=new Worker('./js/worker_apply.js');
webWorkerApply.onmessage = event => { // listen for events from the worker webWorkerApply.onmessage = event => { // listen for events from the worker
//retrieve arraybuffers back from webworker //retrieve arraybuffers back from webworker
if(!el('checkbox-removeheader').checked && !el('checkbox-addheader').checked){ //when adding/removing header we don't need the arraybuffer back if(!el('checkbox-removeheader').checked && !el('checkbox-addheader').checked){ //when adding/removing header we don't need the arraybuffer back since we made a copy previously
romFile._u8array=event.data.romFileU8Array; romFile._u8array=event.data.romFileU8Array;
romFile._dataView=new DataView(romFile._u8array.buffer); romFile._dataView=new DataView(romFile._u8array.buffer);
} }
patchFile._u8array=event.data.patchFileU8Array; patchFile._u8array=event.data.patchFileU8Array;
patchFile._dataView=new DataView(patchFile._u8array.buffer); patchFile._dataView=new DataView(patchFile._u8array.buffer);
if(event.data.patchedRomU8Array)
preparePatchedRom(romFile, new MarcFile(event.data.patchedRomU8Array.buffer), headerSize);
preparePatchedRom(romFile, new MarcFile(event.data.patchedRomU8Array.buffer), headerSize);
setTabApplyEnabled(true); setTabApplyEnabled(true);
if(event.data.errorMessage)
setMessage('apply', _(event.data.errorMessage.replace('Error: ','')), 'error');
else
setMessage('apply');
}; };
webWorkerApply.onerror = event => { // listen for events from the worker webWorkerApply.onerror = event => { // listen for events from the worker
romFile=new MarcFile(el('input-file-rom'), _parseROM);
patchFile=new MarcFile(el('input-file-patch'), _readPatchFile);
setMessage('apply', _(event.message.replace('Error: ','')), 'error');
setTabApplyEnabled(true); setTabApplyEnabled(true);
setMessage('apply', _(event.message.replace('Error: ','')), 'error');
}; };
webWorkerCreate=new Worker('./worker_create.js'); webWorkerCreate=new Worker('./js/worker_create.js');
webWorkerCreate.onmessage = event => { // listen for events from the worker webWorkerCreate.onmessage = event => { // listen for events from the worker
var newPatchFile=new MarcFile(event.data.patchFileU8Array); var newPatchFile=new MarcFile(event.data.patchFileU8Array);
newPatchFile.fileName=romFile2.fileName.replace(/\.[^\.]+$/,'')+'.'+el('select-patch-type').value; newPatchFile.fileName=romFile2.fileName.replace(/\.[^\.]+$/,'')+'.'+el('select-patch-type').value;
@ -61,13 +63,13 @@ try{
setTabCreateEnabled(true); setTabCreateEnabled(true);
}; };
webWorkerCreate.onerror = event => { // listen for events from the worker webWorkerCreate.onerror = event => { // listen for events from the worker
setMessage('create', _(event.message.replace('Error: ','')), 'error');
setTabCreateEnabled(true); setTabCreateEnabled(true);
setMessage('create', _(event.message.replace('Error: ','')), 'error');
}; };
webWorkerCrc=new Worker('./worker_crc.js'); webWorkerCrc=new Worker('./js/worker_crc.js');
webWorkerCrc.onmessage = event => { // listen for events from the worker webWorkerCrc.onmessage = event => { // listen for events from the worker
//console.log('received_crc'); //console.log('received_crc');
el('crc32').innerHTML=padZeroes(event.data.crc32, 4); el('crc32').innerHTML=padZeroes(event.data.crc32, 4);
@ -179,12 +181,12 @@ addEvent(window,'load',function(){
/* zip-js web worker */ /* zip-js web worker */
if(CAN_USE_WEB_WORKERS){ if(CAN_USE_WEB_WORKERS){
zip.useWebWorkers=true; zip.useWebWorkers=true;
zip.workerScriptsPath='./libs/'; zip.workerScriptsPath='./js/zip.js/';
}else{ }else{
zip.useWebWorkers=false; zip.useWebWorkers=false;
var script=document.createElement('script'); var script=document.createElement('script');
script.src='./libs/inflate.js'; script.src='./js/zip.js/inflate.js';
document.getElementsByTagName('head')[0].appendChild(script); document.getElementsByTagName('head')[0].appendChild(script);
} }
@ -213,30 +215,6 @@ addEvent(window,'load',function(){
/* predefined patches: parse URL parameter */
/*if(/\?.*?patch=[^=]+/.test(window.location.href)){
var patchUri=decodeURI(window.location.href.match(/\?.*?patch=([^=]+)/)[1]);
var patchInfo={
patch:patchUri,
name:patchUri
};
if(/\?.*?name=[^=]+/.test(window.location.href)){
patchInfo.name=decodeURI(window.location.href.match(/\?.*?name=([^=]+)/)[1]);
}
if(/\?.*?crc=[0-9a-f]{8}/i.test(window.location.href)){
patchInfo.crc=parseInt(window.location.href.match(/\?.*?patch=([0-9a-f]{8})/)[1], 16);
}
if(typeof PREDEFINED_PATCHES === 'undefined'){
PREDEFINED_PATCHES=[patchInfo];
}else{
PREDEFINED_PATCHES.push(patchInfo);
}
}*/
/* predefined patches */ /* predefined patches */
if(typeof PREDEFINED_PATCHES!=='undefined'){ if(typeof PREDEFINED_PATCHES!=='undefined'){
fetchedPatches={}; fetchedPatches={};
@ -540,10 +518,10 @@ function createPatch(sourceFile, modifiedFile, mode){
if(CAN_USE_WEB_WORKERS){ if(CAN_USE_WEB_WORKERS){
setMessage('create', _('creating_patch'), 'loading');
setTabCreateEnabled(false); setTabCreateEnabled(false);
setMessage('create', _('creating_patch'), 'loading');
webWorkerCreate.postMessage( webWorkerCreate.postMessage(
{ {
sourceFileU8Array:sourceFile._u8array, sourceFileU8Array:sourceFile._u8array,
@ -559,7 +537,6 @@ function createPatch(sourceFile, modifiedFile, mode){
romFile1=new MarcFile(el('input-file-rom1')); romFile1=new MarcFile(el('input-file-rom1'));
romFile2=new MarcFile(el('input-file-rom2')); romFile2=new MarcFile(el('input-file-rom2'));
}else{ }else{
try{ try{
sourceFile.seek(0); sourceFile.seek(0);
modifiedFile.seek(0); modifiedFile.seek(0);

View file

View file

@ -1,4 +1,4 @@
/* IPS module for Rom Patcher JS v20180930 - Marc Robledo 2016-2018 - http://www.marcrobledo.com/license */ /* IPS module for Rom Patcher JS v20200502 - Marc Robledo 2016-2020 - http://www.marcrobledo.com/license */
/* File format specification: http://www.smwiki.net/wiki/IPS_file_format */ /* File format specification: http://www.smwiki.net/wiki/IPS_file_format */
@ -144,11 +144,6 @@ function parseIPSFile(file){
function createIPSFromFiles(original, modified){ function createIPSFromFiles(original, modified){
if(original.fileSize>IPS_MAX_SIZE || modified.fileSize>IPS_MAX_SIZE){
throw new Error('files are too big for IPS format')
}
var patch=new IPS(); var patch=new IPS();
if(modified.fileSize<original.fileSize){ if(modified.fileSize<original.fileSize){
@ -200,6 +195,11 @@ function createIPSFromFiles(original, modified){
previousRecord.length=previousRecord.data.length; previousRecord.length=previousRecord.data.length;
} }
}else{ }else{
if(startOffset>=IPS_MAX_SIZE){
throw new Error('files are too big for IPS format');
return null;
}
if(RLEmode && differentData.length>2){ if(RLEmode && differentData.length>2){
patch.addRLERecord(startOffset, differentData.length, differentData[0]); patch.addRLERecord(startOffset, differentData.length, differentData[0]);
}else{ }else{

83
js/worker_apply.js Normal file
View file

@ -0,0 +1,83 @@
/* Rom Patcher JS v20200502 - Marc Robledo 2016-2020 - http://www.marcrobledo.com/license */
self.importScripts(
'./MarcFile.js',
'./crc.js',
'./formats/ips.js',
'./formats/aps.js',
'./formats/ups.js',
'./formats/bps.js',
'./formats/rup.js',
'./formats/ppf.js',
'./formats/pmsr.js',
'./formats/vcdiff.js'
);
self.onmessage = event => { // listen for messages from the main thread
var romFile=new MarcFile(event.data.romFileU8Array);
var patchFile=new MarcFile(event.data.patchFileU8Array);
var errorMessage=false;
var patch;
var header=patchFile.readString(6);
if(header.startsWith(IPS_MAGIC)){
patch=parseIPSFile(patchFile);
}else if(header.startsWith(UPS_MAGIC)){
patch=parseUPSFile(patchFile);
}else if(header.startsWith(APS_MAGIC)){
patch=parseAPSFile(patchFile);
}else if(header.startsWith(BPS_MAGIC)){
patch=parseBPSFile(patchFile);
}else if(header.startsWith(RUP_MAGIC)){
patch=parseRUPFile(patchFile);
}else if(header.startsWith(PPF_MAGIC)){
patch=parsePPFFile(patchFile);
}else if(header.startsWith(PMSR_MAGIC)){
patch=parseMODFile(patchFile);
}else if(header.startsWith(VCDIFF_MAGIC)){
patch=parseVCDIFF(patchFile);
}else{
errorMessage='error_invalid_patch';
}
//console.log('apply');
var patchedRom;
if(patch){
try{
patchedRom=patch.apply(romFile, event.data.validateChecksums);
}catch(evt){
errorMessage=evt.message;
}
}
//console.log('postMessage');
if(patchedRom){
self.postMessage(
{
romFileU8Array:event.data.romFileU8Array,
patchFileU8Array:event.data.patchFileU8Array,
patchedRomU8Array:patchedRom._u8array,
errorMessage:errorMessage
},
[
event.data.romFileU8Array.buffer,
event.data.patchFileU8Array.buffer,
patchedRom._u8array.buffer
]
);
}else{
self.postMessage(
{
romFileU8Array:event.data.romFileU8Array,
patchFileU8Array:event.data.patchFileU8Array,
errorMessage:errorMessage
},
[
event.data.romFileU8Array.buffer,
event.data.patchFileU8Array.buffer
]
);
}
};

View file

@ -1,7 +1,7 @@
/* Rom Patcher JS v20181018 - Marc Robledo 2016-2018 - http://www.marcrobledo.com/license */ /* Rom Patcher JS v20200502 - Marc Robledo 2016-2020 - http://www.marcrobledo.com/license */
self.importScripts( self.importScripts(
'./libs/MarcFile.js', './MarcFile.js',
'./crc.js' './crc.js'
); );

View file

@ -1,14 +1,14 @@
/* Rom Patcher JS v20181018 - Marc Robledo 2016-2018 - http://www.marcrobledo.com/license */ /* Rom Patcher JS v20200502 - Marc Robledo 2016-2020 - http://www.marcrobledo.com/license */
self.importScripts( self.importScripts(
'./libs/MarcFile.js', './MarcFile.js',
'./crc.js', './crc.js',
'./ips.js', './formats/ips.js',
'./aps.js', './formats/aps.js',
'./ups.js', './formats/ups.js',
'./bps.js', './formats/bps.js',
'./ppf.js', './formats/ppf.js',
'./rup.js' './formats/rup.js'
); );

View file

Before

Width:  |  Height:  |  Size: 202 B

After

Width:  |  Height:  |  Size: 202 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Before After
Before After

View file

@ -1,65 +0,0 @@
/* Rom Patcher JS v20181018 - Marc Robledo 2016-2018 - http://www.marcrobledo.com/license */
self.importScripts(
'./libs/MarcFile.js',
'./crc.js',
'./ips.js',
'./aps.js',
'./ups.js',
'./bps.js',
'./rup.js',
'./ppf.js',
'./pmsr.js',
'./vcdiff.js'
);
self.onmessage = event => { // listen for messages from the main thread
var romFile=new MarcFile(event.data.romFileU8Array);
var patchFile=new MarcFile(event.data.patchFileU8Array);
var patch;
var header=patchFile.readString(6);
if(header.startsWith(IPS_MAGIC)){
patch=parseIPSFile(patchFile);
}else if(header.startsWith(UPS_MAGIC)){
patch=parseUPSFile(patchFile);
}else if(header.startsWith(APS_MAGIC)){
patch=parseAPSFile(patchFile);
}else if(header.startsWith(BPS_MAGIC)){
patch=parseBPSFile(patchFile);
}else if(header.startsWith(RUP_MAGIC)){
patch=parseRUPFile(patchFile);
}else if(header.startsWith(PPF_MAGIC)){
patch=parsePPFFile(patchFile);
}else if(header.startsWith(PMSR_MAGIC)){
patch=parseMODFile(patchFile);
}else if(header.startsWith(VCDIFF_MAGIC)){
patch=parseVCDIFF(patchFile);
}else{
throw new Error('error_invalid_patch');
}
//console.log('apply');
var patchedRom;
try{
patchedRom=patch.apply(romFile, event.data.validateChecksums);
}catch(e){
throw e;
}
//console.log('postMessage');
self.postMessage(
{
romFileU8Array:event.data.romFileU8Array,
patchFileU8Array:event.data.patchFileU8Array,
patchedRomU8Array:patchedRom._u8array
},
[
event.data.romFileU8Array.buffer,
event.data.patchFileU8Array.buffer,
patchedRom._u8array.buffer
]
);
};