mirror of
https://github.com/marcrobledo/RomPatcher.js.git
synced 2025-06-27 16:25:54 +00:00
- feat (web): dynamic JS modules loading
- feat (web): added onloadpatch event - fix (cli): fixed path for JS files
This commit is contained in:
parent
bc82f6d748
commit
de2f0e5c7d
9 changed files with 315 additions and 210 deletions
|
@ -25,7 +25,7 @@ A ROM patcher made in Javascript.
|
|||
Modders and hackers can embed Rom Patcher JS in their websites to provide an online ROM patcher for their patches, allowing users to patch ROMs without downloading any files.<br/>
|
||||
|
||||
- File [`index_template.html`](https://github.com/marcrobledo/RomPatcher.js/blob/master/index_template.html) includes a simple working example
|
||||
- Read [the wiki](https://github.com/marcrobledo/RomPatcher.js/wiki) for more detailed instructions
|
||||
- Read [the wiki](https://github.com/marcrobledo/RomPatcher.js/wiki/Embedding-Rom-Patcher-JS) for more detailed instructions
|
||||
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ Install dependencies:
|
|||
Patch a ROM:
|
||||
> node index.js patch "my_rom.bin" "my_patch.ips"
|
||||
|
||||
Create a patch:
|
||||
Create an IPS patch:
|
||||
> node index.js create "original_rom.bin" modified_rom.bin"
|
||||
|
||||
Show all options:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
var PRECACHE_ID = 'rom-patcher-js';
|
||||
var PRECACHE_VERSION = 'v30beta1b';
|
||||
var PRECACHE_VERSION = 'v30rc1';
|
||||
var PRECACHE_URLS = [
|
||||
'/RomPatcher.js/', '/RomPatcher.js/index.html',
|
||||
'/RomPatcher.js/manifest.json',
|
||||
|
|
29
index.html
29
index.html
|
@ -34,21 +34,6 @@
|
|||
|
||||
<link type="text/css" rel="stylesheet" href="./webapp/style.css" media="all"/>
|
||||
|
||||
|
||||
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/BinFile.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/HashCalculator.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.ips.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.ups.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.aps_n64.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.aps_gba.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.bps.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.rup.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.ppf.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.pmsr.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.vcdiff.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/zip.js/zip.min.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/RomPatcher.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/RomPatcher.webapp.js"></script>
|
||||
<script type="text/javascript" src="./webapp/webapp.js"></script>
|
||||
</head>
|
||||
|
@ -67,7 +52,7 @@
|
|||
<div class="row m-b" id="rom-patcher-row-file-rom">
|
||||
<div class="text-right"><label for="rom-patcher-input-file-rom" data-localize="yes">ROM file:</label></div>
|
||||
<div class="rom-patcher-container-input">
|
||||
<input type="file" id="rom-patcher-input-file-rom" class="w100 empty" />
|
||||
<input type="file" id="rom-patcher-input-file-rom" class="empty" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-b" id="rom-patcher-row-alter-header">
|
||||
|
@ -98,7 +83,7 @@
|
|||
<div class="row m-b" id="rom-patcher-row-file-patch">
|
||||
<div class="text-right"><label for="rom-patcher-input-file-patch" data-localize="yes">Patch file:</label></div>
|
||||
<div class="rom-patcher-container-input">
|
||||
<input type="file" id="rom-patcher-input-file-patch" class="w100 empty" accept=".ips,.ups,.bps,.aps,.rup,.ppf,.mod,.xdelta,.vcdiff,.zip" />
|
||||
<input type="file" id="rom-patcher-input-file-patch" class="empty" accept=".ips,.ups,.bps,.aps,.rup,.ppf,.mod,.xdelta,.vcdiff,.zip" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-b" id="rom-patcher-row-patch-description">
|
||||
|
@ -120,21 +105,21 @@
|
|||
<div class="row m-b">
|
||||
<div class="text-right"><label for="patch-builder-input-file-original" data-localize="yes" >Original ROM:</label></div>
|
||||
<div>
|
||||
<input type="file" id="patch-builder-input-file-original" class="w100 empty" />
|
||||
<input type="file" id="patch-builder-input-file-original" class="empty" disabled />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row m-b">
|
||||
<div class="text-right"><label for="patch-builder-input-file-modified" data-localize="yes">Modified ROM:</label></div>
|
||||
<div>
|
||||
<input type="file" id="patch-builder-input-file-modified" class="w100 empty" />
|
||||
<input type="file" id="patch-builder-input-file-modified" class="empty" disabled />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row m-b">
|
||||
<div class="text-right"><label for="patch-builder-select-patch-type" data-localize="yes">Patch type:</label></div>
|
||||
<div>
|
||||
<select id="patch-builder-select-patch-type">
|
||||
<select id="patch-builder-select-patch-type" disabled>
|
||||
<option value="ips">IPS</option>
|
||||
<option value="bps">BPS</option>
|
||||
<option value="ppf">PPF</option>
|
||||
|
@ -147,7 +132,7 @@
|
|||
|
||||
<div class="buttons text-center">
|
||||
<div id="patch-builder-row-error-message" class="m-b"><span id="patch-builder-error-message"></span></div>
|
||||
<button id="patch-builder-button-create" disabled data-localize="yes">Create patch</button>
|
||||
<button id="patch-builder-button-create" disabled data-localize="yes" disabled>Create patch</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -166,7 +151,7 @@
|
|||
<button id="button-settings" class="btn-transparent"><img src="./webapp/icon_settings.svg" loading="lazy" class="icon settings" /> <span data-localize="yes">Settings</span></button>
|
||||
</div>
|
||||
|
||||
Rom Patcher JS <small>v3.0 <a style="color:rgb(255, 197, 7)" href="legacy/" rel="nofollow">Beta 1</a></small> by <a href="/">Marc Robledo</a>
|
||||
Rom Patcher JS <small>v3.0 <a style="color:rgb(255, 197, 7)" href="legacy/" rel="nofollow">RC1</a></small> by <a href="/">Marc Robledo</a>
|
||||
<br />
|
||||
<img src="./webapp/icon_github.svg" loading="lazy" class="icon github" /> <a href="https://github.com/marcrobledo/RomPatcher.js/" target="_blank">See on GitHub</a>
|
||||
<img src="./webapp/icon_heart.svg" loading="lazy" class="icon heart" /> <a href="https://www.paypal.me/marcrobledo/5" target="_blank" rel="nofollow">Donate</a>
|
||||
|
|
|
@ -10,22 +10,9 @@
|
|||
|
||||
<!-- Rom Patcher JS needed CSS/JS files -->
|
||||
<link type="text/css" rel="stylesheet" href="./rom-patcher-js/style.css" media="all" />
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/BinFile.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/HashCalculator.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.ips.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.ups.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.aps_n64.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.aps_gba.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.bps.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.rup.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.ppf.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.pmsr.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/RomPatcher.format.vcdiff.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/modules/zip.js/zip.min.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/RomPatcher.js"></script>
|
||||
<script type="text/javascript" src="./rom-patcher-js/RomPatcher.webapp.js"></script>
|
||||
|
||||
<!-- Rom Patcher JS initizlization -->
|
||||
<!-- Rom Patcher JS initialization -->
|
||||
<script type="text/javascript">
|
||||
window.addEventListener('load', function (evt) {
|
||||
try {
|
||||
|
@ -70,7 +57,7 @@
|
|||
<div class="rom-patcher-row margin-bottom" id="rom-patcher-row-file-rom">
|
||||
<div class="text-right"><label for="rom-patcher-input-file-rom" data-localize="yes">ROM file:</label></div>
|
||||
<div class="rom-patcher-container-input">
|
||||
<input type="file" id="rom-patcher-input-file-rom" class="empty" />
|
||||
<input type="file" id="rom-patcher-input-file-rom" class="empty" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="margin-bottom text-selectable text-mono text-muted" id="rom-patcher-rom-info">
|
||||
|
@ -97,7 +84,7 @@
|
|||
</div>
|
||||
<div class="rom-patcher-container-input">
|
||||
<input type="file" id="rom-patcher-input-file-patch" class="empty"
|
||||
accept=".ips,.ups,.bps,.aps,.rup,.ppf,.mod,.xdelta,.vcdiff,.zip" />
|
||||
accept=".ips,.ups,.bps,.aps,.rup,.ppf,.mod,.xdelta,.vcdiff,.zip" disabled />
|
||||
</div>
|
||||
</div>
|
||||
<div class="rom-patcher-row margin-bottom" id="rom-patcher-row-patch-description">
|
||||
|
|
|
@ -31,14 +31,29 @@
|
|||
|
||||
/*
|
||||
to-do list:
|
||||
- load JS modules dynamically when RomPatchwerWeb is initialized
|
||||
- allow multiple instances of RomPatcherWeb
|
||||
- allow multiple instances of RomPatcherWeb?
|
||||
- switch to ES6 classes and modules?
|
||||
*/
|
||||
|
||||
const ROM_PATCHER_JS_PATH = './rom-patcher-js/';
|
||||
|
||||
var RomPatcherWeb = (function () {
|
||||
const SCRIPT_DEPENDENCIES = [
|
||||
'modules/BinFile.js',
|
||||
'modules/HashCalculator.js',
|
||||
'modules/RomPatcher.format.ips.js',
|
||||
'modules/RomPatcher.format.ups.js',
|
||||
'modules/RomPatcher.format.aps_n64.js',
|
||||
'modules/RomPatcher.format.aps_gba.js',
|
||||
'modules/RomPatcher.format.bps.js',
|
||||
'modules/RomPatcher.format.rup.js',
|
||||
'modules/RomPatcher.format.ppf.js',
|
||||
'modules/RomPatcher.format.pmsr.js',
|
||||
'modules/RomPatcher.format.vcdiff.js',
|
||||
'modules/zip.js/zip.min.js',
|
||||
'RomPatcher.js'
|
||||
];
|
||||
|
||||
const WEB_CRYPTO_AVAILABLE = window.crypto && window.crypto.subtle && window.crypto.subtle.digest;
|
||||
const settings = {
|
||||
language: typeof navigator.language === 'string' ? navigator.language.substring(0, 2) : 'en',
|
||||
|
@ -49,6 +64,7 @@ var RomPatcherWeb = (function () {
|
|||
|
||||
onloadrom: null,
|
||||
onvalidaterom: null,
|
||||
onloadpatch: null,
|
||||
onpatch: null
|
||||
};
|
||||
var romFile, patch;
|
||||
|
@ -384,10 +400,6 @@ var RomPatcherWeb = (function () {
|
|||
webWorkerCrc.onerror = event => { // listen for events from the worker
|
||||
_setToastError('webWorkerCrc error: ' + event.message);
|
||||
};
|
||||
/* zip-js web worker */
|
||||
zip.useWebWorkers = true;
|
||||
zip.workerScriptsPath = ROM_PATCHER_JS_PATH + 'modules/zip.js/';
|
||||
|
||||
|
||||
const _getChecksumStartOffset = function () {
|
||||
if (romFile) {
|
||||
|
@ -402,12 +414,177 @@ var RomPatcherWeb = (function () {
|
|||
}
|
||||
|
||||
|
||||
const _getScriptPath = function () {
|
||||
const currentScripts = document.querySelectorAll('script');
|
||||
var scriptPath;
|
||||
if (document.currentScript) {
|
||||
scriptPath = document.currentScript.src;
|
||||
} else {
|
||||
for (var i = 0; i < currentScripts.length; i++) {
|
||||
if (currentScripts[i].src.indexOf('RomPatcher.webapp.js') !== -1) {
|
||||
scriptPath = currentScripts[i].src;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!scriptPath)
|
||||
scriptPath = './rom-patcher-js/';
|
||||
}
|
||||
return scriptPath.substring(0, scriptPath.lastIndexOf('/') + 1);
|
||||
}
|
||||
const _getMissingDependencies = function () {
|
||||
const currentScripts = document.querySelectorAll('script');
|
||||
const scriptPath = _getScriptPath();
|
||||
var missingDependencies = [];
|
||||
for (var i = 0; i < SCRIPT_DEPENDENCIES.length && !isLoaded; i++) {
|
||||
var isLoaded = false;
|
||||
for (var j = 0; j < currentScripts.length; j++) {
|
||||
if (currentScripts[j].src === scriptPath + SCRIPT_DEPENDENCIES[i])
|
||||
isLoaded = true;
|
||||
}
|
||||
if (!isLoaded)
|
||||
missingDependencies.push(scriptPath + SCRIPT_DEPENDENCIES[i]);
|
||||
}
|
||||
|
||||
return missingDependencies;
|
||||
}
|
||||
const _initialize = function (newSettings, embededPatchInfo) {
|
||||
/* embeded patches */
|
||||
var validEmbededPatch = false;
|
||||
if (embededPatchInfo) {
|
||||
if (typeof embededPatchInfo === 'string')
|
||||
embededPatchInfo = { file: embededPatchInfo };
|
||||
|
||||
if (typeof embededPatchInfo === 'object') {
|
||||
if (typeof embededPatchInfo.file === 'string') {
|
||||
validEmbededPatch = true;
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: invalid embeded patch file');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* check if Rom Patcher JS core is available */
|
||||
if (typeof RomPatcher !== 'object') {
|
||||
throw new Error('Rom Patcher JS: core not found');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* check if zip-js web worker is available */
|
||||
if (typeof zip !== 'object' || typeof zip.useWebWorkers !== 'boolean') {
|
||||
throw new Error('Rom Patcher JS: zip.js web worker not found');
|
||||
}
|
||||
zip.useWebWorkers = true;
|
||||
zip.workerScriptsPath = ROM_PATCHER_JS_PATH + 'modules/zip.js/';
|
||||
|
||||
/* check if all required HTML elements are in DOM */
|
||||
const htmlInputFileRom = htmlElements.get('input-file-rom');
|
||||
if (htmlInputFileRom && htmlInputFileRom.tagName === 'INPUT' && htmlInputFileRom.type === 'file') {
|
||||
htmlInputFileRom.addEventListener('change', function (evt) {
|
||||
htmlElements.disableAll();
|
||||
new BinFile(this, RomPatcherWeb.provideRomFile);
|
||||
});
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: input#rom-patcher-input-file-rom[type=file] not found');
|
||||
}
|
||||
const htmlInputFilePatch = htmlElements.get('input-file-patch');
|
||||
if (htmlInputFilePatch && htmlInputFilePatch.tagName === 'INPUT' && htmlInputFilePatch.type === 'file') {
|
||||
htmlInputFilePatch.addEventListener('change', function (evt) {
|
||||
htmlElements.disableAll();
|
||||
new BinFile(this, RomPatcherWeb.providePatchFile);
|
||||
});
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: input#rom-patcher-input-file-patch[type=file] not found');
|
||||
}
|
||||
const htmlButtonApply = htmlElements.get('button-apply');
|
||||
if (htmlButtonApply && htmlButtonApply.tagName === 'BUTTON') {
|
||||
htmlButtonApply.addEventListener('click', RomPatcherWeb.applyPatch);
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: button#rom-patcher-button-apply not found');
|
||||
}
|
||||
const htmlCheckboxAlterHeader = htmlElements.get('checkbox-alter-header');
|
||||
if (htmlCheckboxAlterHeader && htmlCheckboxAlterHeader.tagName === 'INPUT' && htmlCheckboxAlterHeader.type === 'checkbox') {
|
||||
htmlCheckboxAlterHeader.addEventListener('change', function (evt) {
|
||||
if (!romFile)
|
||||
return false;
|
||||
|
||||
const headerInfo = RomPatcher.isRomHeadered(romFile);
|
||||
if (headerInfo) {
|
||||
htmlElements.disableAll();
|
||||
webWorkerCrc.postMessage({ u8array: romFile._u8array, fileName: romFile.fileName, checksumStartOffset: _getChecksumStartOffset() }, [romFile._u8array.buffer]);
|
||||
}
|
||||
});
|
||||
}
|
||||
/* set all default input status just in case HTML is wrong */
|
||||
htmlElements.disableAll();
|
||||
/* reset input files */
|
||||
htmlElements.setValue('input-file-rom', '');
|
||||
htmlElements.setValue('input-file-patch', '');
|
||||
|
||||
|
||||
/* translatable elements */
|
||||
const translatableElements = document.querySelectorAll('*[data-localize="yes"]');
|
||||
for (var i = 0; i < translatableElements.length; i++) {
|
||||
translatableElements[i].setAttribute('data-localize', translatableElements[i].innerHTML);
|
||||
}
|
||||
|
||||
/* add drag and drop events */
|
||||
if (newSettings && newSettings.allowDropFiles) {
|
||||
window.addEventListener('dragover', function (evt) {
|
||||
if (_dragEventContainsFiles(evt))
|
||||
evt.preventDefault(); /* needed ! */
|
||||
});
|
||||
window.addEventListener('drop', function (evt) {
|
||||
evt.preventDefault();
|
||||
if (_dragEventContainsFiles(evt)) {
|
||||
const droppedFiles = evt.dataTransfer.files;
|
||||
if (droppedFiles && droppedFiles.length === 1) {
|
||||
new BinFile(droppedFiles[0], function (binFile) {
|
||||
if (RomPatcherWeb.getEmbededPatches()) {
|
||||
RomPatcherWeb.provideRomFile(binFile, true);
|
||||
} else if (ZIPManager.isZipFile(binFile)) {
|
||||
ZIPManager.unzipAny(binFile._u8array.buffer);
|
||||
} else if (RomPatcher.parsePatchFile(binFile)) {
|
||||
RomPatcherWeb.providePatchFile(binFile, null, true);
|
||||
} else {
|
||||
RomPatcherWeb.provideRomFile(binFile, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
htmlInputFileRom.addEventListener('drop', function (evt) {
|
||||
evt.stopPropagation();
|
||||
});
|
||||
htmlInputFilePatch.addEventListener('drop', function (evt) {
|
||||
evt.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Rom Patcher JS initialized');
|
||||
initialized = true;
|
||||
|
||||
|
||||
/* initialize Rom Patcher */
|
||||
RomPatcherWeb.setSettings(newSettings);
|
||||
|
||||
/* download embeded patch */
|
||||
if (validEmbededPatch)
|
||||
_fetchPatchFile(embededPatchInfo);
|
||||
else
|
||||
htmlElements.enableAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* localization */
|
||||
const _ = function (str) { return ROM_PATCHER_LOCALE[settings.language] && ROM_PATCHER_LOCALE[settings.language][str] ? ROM_PATCHER_LOCALE[settings.language][str] : str };
|
||||
|
||||
|
||||
var initialized = false;
|
||||
var loading = 0;
|
||||
return {
|
||||
_: function (str) { /* public localization function for external usage purposes */
|
||||
return _(str);
|
||||
|
@ -562,6 +739,10 @@ var RomPatcherWeb = (function () {
|
|||
|
||||
RomPatcherWeb.validateCurrentRom(_getChecksumStartOffset());
|
||||
|
||||
if (typeof settings.onloadpatch === 'function') {
|
||||
settings.onloadpatch(binFile, embededPatchInfo, parsedPatch);
|
||||
}
|
||||
|
||||
if (transferFakeFile) {
|
||||
htmlElements.setFakeFile('input-file-patch', binFile.fileName);
|
||||
}
|
||||
|
@ -606,21 +787,9 @@ var RomPatcherWeb = (function () {
|
|||
initialize: function (newSettings, embededPatchInfo) {
|
||||
if (initialized)
|
||||
throw new Error('Rom Patcher JS was already initialized');
|
||||
else if (loading)
|
||||
throw new Error('Rom Patcher JS is already loading or has failed to load');
|
||||
|
||||
/* embeded patches */
|
||||
var validEmbededPatch = false;
|
||||
if (embededPatchInfo) {
|
||||
if (typeof embededPatchInfo === 'string')
|
||||
embededPatchInfo = { file: embededPatchInfo };
|
||||
|
||||
if (typeof embededPatchInfo === 'object') {
|
||||
if (typeof embededPatchInfo.file === 'string') {
|
||||
validEmbededPatch = true;
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: invalid embeded patch file');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check incompatible browsers */
|
||||
if (
|
||||
|
@ -633,101 +802,32 @@ var RomPatcherWeb = (function () {
|
|||
throw new Error('Rom Patcher JS: incompatible browser');
|
||||
|
||||
|
||||
|
||||
/* check if all required HTML elements are in DOM */
|
||||
const htmlInputFileRom = htmlElements.get('input-file-rom');
|
||||
if (htmlInputFileRom && htmlInputFileRom.tagName === 'INPUT' && htmlInputFileRom.type === 'file') {
|
||||
htmlInputFileRom.addEventListener('change', function (evt) {
|
||||
/* queue script dependencies */
|
||||
const missingDependencies = _getMissingDependencies();
|
||||
loading = missingDependencies.length;
|
||||
const onLoadScript = function () {
|
||||
loading--;
|
||||
if (loading === 0) {
|
||||
try {
|
||||
_initialize(newSettings, embededPatchInfo);
|
||||
} catch (ex) {
|
||||
_setToastError(ex.message);
|
||||
htmlElements.disableAll();
|
||||
new BinFile(this, RomPatcherWeb.provideRomFile);
|
||||
});
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: input#rom-patcher-input-file-rom[type=file] not found');
|
||||
}
|
||||
const htmlInputFilePatch = htmlElements.get('input-file-patch');
|
||||
if (htmlInputFilePatch && htmlInputFilePatch.tagName === 'INPUT' && htmlInputFilePatch.type === 'file') {
|
||||
htmlInputFilePatch.addEventListener('change', function (evt) {
|
||||
htmlElements.disableAll();
|
||||
new BinFile(this, RomPatcherWeb.providePatchFile);
|
||||
});
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: input#rom-patcher-input-file-patch[type=file] not found');
|
||||
}
|
||||
const htmlButtonApply = htmlElements.get('button-apply');
|
||||
if (htmlButtonApply && htmlButtonApply.tagName === 'BUTTON') {
|
||||
htmlButtonApply.addEventListener('click', RomPatcherWeb.applyPatch);
|
||||
} else {
|
||||
throw new Error('Rom Patcher JS: button#rom-patcher-button-apply not found');
|
||||
}
|
||||
const htmlCheckboxAlterHeader = htmlElements.get('checkbox-alter-header');
|
||||
if (htmlCheckboxAlterHeader && htmlCheckboxAlterHeader.tagName === 'INPUT' && htmlCheckboxAlterHeader.type === 'checkbox') {
|
||||
htmlCheckboxAlterHeader.addEventListener('change', function (evt) {
|
||||
if (!romFile)
|
||||
return false;
|
||||
};
|
||||
const onErrorScript = function () {
|
||||
throw new Error('Rom Patcher JS: error loading script ' + script.src);
|
||||
};
|
||||
console.log('Rom Patcher JS: loading ' + missingDependencies.length + ' dependencies');
|
||||
missingDependencies.forEach(function (path) {
|
||||
var script = document.createElement('script');
|
||||
script.onload = onLoadScript;
|
||||
script.onerror = onErrorScript;
|
||||
script.src = path;
|
||||
|
||||
const headerInfo = RomPatcher.isRomHeadered(romFile);
|
||||
if (headerInfo) {
|
||||
htmlElements.disableAll();
|
||||
webWorkerCrc.postMessage({ u8array: romFile._u8array, fileName: romFile.fileName, checksumStartOffset: _getChecksumStartOffset() }, [romFile._u8array.buffer]);
|
||||
}
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
/* set all default input status just in case HTML is wrong */
|
||||
htmlElements.setEnabled('button-apply', false);
|
||||
/* reset input files */
|
||||
htmlElements.setValue('input-file-rom', '');
|
||||
htmlElements.setValue('input-file-patch', '');
|
||||
|
||||
|
||||
/* translatable elements */
|
||||
const translatableElements = document.querySelectorAll('*[data-localize="yes"]');
|
||||
for (var i = 0; i < translatableElements.length; i++) {
|
||||
translatableElements[i].setAttribute('data-localize', translatableElements[i].innerHTML);
|
||||
}
|
||||
|
||||
/* add drag and drop events */
|
||||
if (newSettings && newSettings.allowDropFiles) {
|
||||
window.addEventListener('dragover', function (evt) {
|
||||
if (_dragEventContainsFiles(evt))
|
||||
evt.preventDefault(); /* needed ! */
|
||||
});
|
||||
window.addEventListener('drop', function (evt) {
|
||||
evt.preventDefault();
|
||||
if (_dragEventContainsFiles(evt)) {
|
||||
const droppedFiles = evt.dataTransfer.files;
|
||||
if (droppedFiles && droppedFiles.length === 1) {
|
||||
new BinFile(droppedFiles[0], function (binFile) {
|
||||
if (RomPatcherWeb.getEmbededPatches()) {
|
||||
RomPatcherWeb.provideRomFile(binFile, true);
|
||||
} else if (ZIPManager.isZipFile(binFile)) {
|
||||
ZIPManager.unzipAny(binFile._u8array.buffer);
|
||||
} else if (RomPatcher.parsePatchFile(binFile)) {
|
||||
RomPatcherWeb.providePatchFile(binFile, null, true);
|
||||
} else {
|
||||
RomPatcherWeb.provideRomFile(binFile, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
htmlInputFileRom.addEventListener('drop', function (evt) {
|
||||
evt.stopPropagation();
|
||||
});
|
||||
htmlInputFilePatch.addEventListener('drop', function (evt) {
|
||||
evt.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Rom Patcher JS initialized');
|
||||
initialized = true;
|
||||
|
||||
|
||||
/* initialize Rom Patcher */
|
||||
RomPatcherWeb.setSettings(newSettings);
|
||||
|
||||
/* download embeded patch */
|
||||
if (validEmbededPatch)
|
||||
_fetchPatchFile(embededPatchInfo);
|
||||
},
|
||||
|
||||
applyPatch: function () {
|
||||
|
@ -859,6 +959,11 @@ var RomPatcherWeb = (function () {
|
|||
else if (typeof newSettings.onvalidaterom !== 'undefined')
|
||||
settings.onvalidaterom = null;
|
||||
|
||||
if (typeof newSettings.onloadpatch === 'function')
|
||||
settings.onloadpatch = newSettings.onloadpatch;
|
||||
else if (typeof newSettings.onloadpatch !== 'undefined')
|
||||
settings.onloadpatch = null;
|
||||
|
||||
if (typeof newSettings.onpatch === 'function')
|
||||
settings.onpatch = newSettings.onpatch;
|
||||
else if (typeof newSettings.onpatch !== 'undefined')
|
||||
|
@ -935,9 +1040,9 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
|
||||
const _unzipEntry = function (zippedEntry, onUnzip) {
|
||||
htmlElements.disableAll();
|
||||
if (onUnzip === RomPatcherWeb.provideRomFile) {
|
||||
if (onUnzip === romPatcherWeb.provideRomFile) {
|
||||
_setRomInputSpinner(true);
|
||||
} else if (onUnzip === RomPatcherWeb.providePatchFile) {
|
||||
} else if (onUnzip === romPatcherWeb.providePatchFile) {
|
||||
_setPatchInputSpinner(true);
|
||||
} else {
|
||||
throw new Error('ZIPManager._unzipEntry: invalid onUnzip callback');
|
||||
|
@ -949,7 +1054,7 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
binFile.fileName = zippedEntry.filename;
|
||||
|
||||
/* transfer files to input elements */
|
||||
if (onUnzip === RomPatcherWeb.provideRomFile) {
|
||||
if (onUnzip === romPatcherWeb.provideRomFile) {
|
||||
_setRomInputSpinner(false);
|
||||
onUnzip(binFile, true);
|
||||
} else {
|
||||
|
@ -971,9 +1076,9 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
_unzipEntry(this.zipEntry, onUnzip);
|
||||
}
|
||||
|
||||
if (onUnzip === RomPatcherWeb.provideRomFile) {
|
||||
if (onUnzip === romPatcherWeb.provideRomFile) {
|
||||
dialogZipMessage.innerHTML = _('ROM file:');
|
||||
} else if (onUnzip === RomPatcherWeb.providePatchFile) {
|
||||
} else if (onUnzip === romPatcherWeb.providePatchFile) {
|
||||
dialogZipMessage.innerHTML = _('Patch file:');
|
||||
} else {
|
||||
throw new Error('ZIPManager._unzipEntry: invalid onUnzip callback');
|
||||
|
@ -1022,8 +1127,8 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
const _unzipError = function (zipReader) {
|
||||
if (zipReader.message)
|
||||
console.error('zip.js: ' + zipReader.message);
|
||||
RomPatcherWeb.enable();
|
||||
RomPatcherWeb.setErrorMessage(_('Error unzipping file'), 'error');
|
||||
romPatcherWeb.enable();
|
||||
romPatcherWeb.setErrorMessage(_('Error unzipping file'), 'error');
|
||||
};
|
||||
|
||||
|
||||
|
@ -1042,13 +1147,13 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
const filteredEntries = _filterEntriesRoms(zipEntries);
|
||||
|
||||
if (filteredEntries.length === 1) {
|
||||
_unzipEntry(filteredEntries[0], RomPatcherWeb.provideRomFile);
|
||||
_unzipEntry(filteredEntries[0], romPatcherWeb.provideRomFile);
|
||||
} else if (filteredEntries.length > 1) {
|
||||
_showFilePicker(filteredEntries, RomPatcherWeb.provideRomFile);
|
||||
RomPatcherWeb.enable();
|
||||
_showFilePicker(filteredEntries, romPatcherWeb.provideRomFile);
|
||||
romPatcherWeb.enable();
|
||||
} else {
|
||||
/* no possible patchable files found in zip, treat zip file as ROM file */
|
||||
RomPatcherWeb.calculateCurrentRomChecksums();
|
||||
romPatcherWeb.calculateCurrentRomChecksums();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -1066,11 +1171,11 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
const filteredEntries = _filterEntriesPatches(zipEntries);
|
||||
|
||||
if (filteredEntries.length === 1) {
|
||||
_unzipEntry(filteredEntries[0], RomPatcherWeb.providePatchFile);
|
||||
_unzipEntry(filteredEntries[0], romPatcherWeb.providePatchFile);
|
||||
} else if (filteredEntries.length > 1) {
|
||||
_showFilePicker(filteredEntries, RomPatcherWeb.providePatchFile);
|
||||
_showFilePicker(filteredEntries, romPatcherWeb.providePatchFile);
|
||||
} else {
|
||||
RomPatcherWeb.providePatchFile(null);
|
||||
romPatcherWeb.providePatchFile(null);
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -1091,16 +1196,16 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
|
||||
if (filteredEntriesRoms.length && filteredEntriesPatches.length === 0) {
|
||||
if (filteredEntriesRoms.length === 1) {
|
||||
_unzipEntry(filteredEntriesRoms[0], RomPatcherWeb.provideRomFile);
|
||||
_unzipEntry(filteredEntriesRoms[0], romPatcherWeb.provideRomFile);
|
||||
} else {
|
||||
_showFilePicker(filteredEntriesRoms, RomPatcherWeb.provideRomFile);
|
||||
RomPatcherWeb.enable();
|
||||
_showFilePicker(filteredEntriesRoms, romPatcherWeb.provideRomFile);
|
||||
romPatcherWeb.enable();
|
||||
}
|
||||
} else if (filteredEntriesPatches.length && filteredEntriesRoms.length === 0) {
|
||||
if (filteredEntriesPatches.length === 1) {
|
||||
_unzipEntry(filteredEntriesPatches[0], RomPatcherWeb.providePatchFile);
|
||||
_unzipEntry(filteredEntriesPatches[0], romPatcherWeb.providePatchFile);
|
||||
} else {
|
||||
_showFilePicker(filteredEntriesPatches, RomPatcherWeb.providePatchFile);
|
||||
_showFilePicker(filteredEntriesPatches, romPatcherWeb.providePatchFile);
|
||||
}
|
||||
} else {
|
||||
console.warn('ZIPManager.unzipAny: zip file contains both ROMs and patches, cannot guess');
|
||||
|
@ -1149,7 +1254,7 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
|
||||
select.addEventListener('change', function (evt) {
|
||||
const fileIndex = parseInt(this.value);
|
||||
_unzipEntry(filteredEntries[fileIndex], RomPatcherWeb.providePatchFile);
|
||||
_unzipEntry(filteredEntries[fileIndex], romPatcherWeb.providePatchFile);
|
||||
});
|
||||
} else {
|
||||
throw new Error('rom-patcher-select-file-patch not found');
|
||||
|
@ -1157,10 +1262,10 @@ const ZIPManager = (function (romPatcherWeb) {
|
|||
}
|
||||
|
||||
//_setPatchInputSpinner(false);
|
||||
_unzipEntry(filteredEntries[0], RomPatcherWeb.providePatchFile);
|
||||
_unzipEntry(filteredEntries[0], romPatcherWeb.providePatchFile);
|
||||
} else {
|
||||
RomPatcherWeb.setErrorMessage(_('No valid patches found in ZIP'), 'error');
|
||||
RomPatcherWeb.disable();
|
||||
romPatcherWeb.setErrorMessage(_('No valid patches found in ZIP'), 'error');
|
||||
romPatcherWeb.disable();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -1258,6 +1363,8 @@ const PatchBuilderWeb = (function (romPatcherWeb) {
|
|||
initialize: function () {
|
||||
if (initialized)
|
||||
throw new Error('Patch Builder JS was already initialized');
|
||||
else if (!romPatcherWeb.isInitialized())
|
||||
throw new Error('Rom Patcher JS must be initialized before Patch Builder JS');
|
||||
|
||||
document.getElementById('patch-builder-button-create').disabled = true;
|
||||
|
||||
|
@ -1269,6 +1376,8 @@ const PatchBuilderWeb = (function (romPatcherWeb) {
|
|||
|
||||
if (RomPatcher.isRomTooBig(originalRom))
|
||||
_setToastError(_('Using big files is not recommended'), 'warning');
|
||||
else if (ZIPManager.isZipFile(originalRom))
|
||||
_setToastError(_('Patch creation is not compatible with zipped ROMs'), 'warning');
|
||||
});
|
||||
});
|
||||
document.getElementById('patch-builder-input-file-modified').addEventListener('change', function () {
|
||||
|
@ -1279,6 +1388,8 @@ const PatchBuilderWeb = (function (romPatcherWeb) {
|
|||
|
||||
if (RomPatcher.isRomTooBig(modifiedRom))
|
||||
_setToastError(_('Using big files is not recommended'), 'warning');
|
||||
else if (ZIPManager.isZipFile(modifiedRom))
|
||||
_setToastError(_('Patch creation is not compatible with zipped ROMs'), 'warning');
|
||||
});
|
||||
});
|
||||
document.getElementById('patch-builder-button-create').addEventListener('click', function () {
|
||||
|
@ -1298,6 +1409,7 @@ const PatchBuilderWeb = (function (romPatcherWeb) {
|
|||
|
||||
console.log('Patch Builder JS initialized');
|
||||
initialized = true;
|
||||
_setElementsStatus(true);
|
||||
}
|
||||
}
|
||||
}(RomPatcherWeb));
|
||||
|
|
|
@ -184,14 +184,19 @@ VCDIFF.fromFile=function(file){
|
|||
|
||||
function VCDIFF_Parser(binFile, offset)
|
||||
{
|
||||
BinFile.call(this, 0);
|
||||
this.fileSize=binFile.fileSize;
|
||||
this._u8array=binFile._u8array;
|
||||
this._dataView=binFile._dataView;
|
||||
this.offset=offset || 0;
|
||||
}
|
||||
|
||||
VCDIFF_Parser.prototype=Object.create(BinFile.prototype);
|
||||
/* reimplement readU8, readU32 and skip from BinFile */
|
||||
/* in web implementation, there are no guarantees BinFile will be dynamically loaded before this one */
|
||||
/* so we cannot rely on cloning BinFile.prototype */
|
||||
this.readU8 = binFile.readU8;
|
||||
this.readU32 = binFile.readU32;
|
||||
this.skip = binFile.skip;
|
||||
this.isEOF = binFile.isEOF;
|
||||
this.seek = binFile.seek;
|
||||
}
|
||||
VCDIFF_Parser.prototype.read7BitEncodedInt=function(){
|
||||
var num=0, bits = 0;
|
||||
|
||||
|
|
18
test.js
18
test.js
|
@ -24,14 +24,17 @@
|
|||
- RUP test
|
||||
- Patch: https://www.romhacking.net/translations/843/
|
||||
- ROM: Uchuu no Kishi - Tekkaman Blade (Japan).sfc [CRC32=cd16c529]
|
||||
- xdelta test
|
||||
- Patch: https://www.romhacking.net/hacks/2871/
|
||||
- ROM: New Super Mario Bros. (USA, Australia).nds [CRC32=0197576a]
|
||||
*/
|
||||
|
||||
const chalk=require('chalk');
|
||||
const { existsSync }=require('fs');
|
||||
|
||||
const BinFile = require('./app/modules/BinFile');
|
||||
const HashCalculator = require('./app/modules/HashCalculator');
|
||||
const RomPatcher = require('./app/RomPatcher');
|
||||
const BinFile = require('./rom-patcher-js/modules/BinFile');
|
||||
const HashCalculator = require('./rom-patcher-js/modules/HashCalculator');
|
||||
const RomPatcher = require('./rom-patcher-js/RomPatcher');
|
||||
|
||||
|
||||
|
||||
|
@ -77,10 +80,17 @@ const TEST_PATCHES=[
|
|||
patchCrc32:0x621ab323,
|
||||
patchDownload:'https://www.romhacking.net/hacks/4633/',
|
||||
outputCrc32:0xe83e9b0a
|
||||
},{
|
||||
title:'NSMB Hack Domain Infusion',
|
||||
romFile:'New Super Mario Bros. (USA, Australia).nds',
|
||||
romCrc32:0x0197576a,
|
||||
patchFile:'nsmb_infusion10a.xdelta',
|
||||
patchCrc32:0xa211f97c,
|
||||
patchDownload:'https://www.romhacking.net/hacks/2871/',
|
||||
outputCrc32:0x9cecd976
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
const _test=function(title, testFunction){
|
||||
try{
|
||||
const startTime=(new Date()).getTime();
|
||||
|
|
|
@ -208,7 +208,10 @@ select:focus:not(:disabled),
|
|||
input[type=checkbox].styled:focus:not(:disabled){
|
||||
box-shadow: var(--rom-patcher-color-primary-focus) 0 0 0 2px;
|
||||
}
|
||||
input[type=file].w100, select.w100{width:100%}
|
||||
#rom-patcher-container input[type=file],
|
||||
#rom-patcher-container select,
|
||||
#patch-builder-container input[type=file]
|
||||
{width:100%}
|
||||
input[type=file]{padding:6px 10px}
|
||||
input[type=file]::file-selector-button{display:none}
|
||||
select{
|
||||
|
|
|
@ -101,6 +101,9 @@ window.addEventListener('load', function (evt) {
|
|||
});
|
||||
|
||||
document.getElementById('switch-create-button').addEventListener('click', function () {
|
||||
if(!RomPatcherWeb.isInitialized())
|
||||
throw new Error('Rom Patcher JS is not initialized yet');
|
||||
|
||||
if (/disabled/.test(document.getElementById('switch-create').className)) {
|
||||
try{
|
||||
if(!PatchBuilderWeb.isInitialized())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue