mirror of
https://github.com/marcrobledo/RomPatcher.js.git
synced 2025-06-27 16:25:54 +00:00
adding command line support
This commit is contained in:
parent
c87df560e9
commit
faee7e6a43
18 changed files with 557 additions and 40 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
*.gba
|
||||||
|
*.sav
|
||||||
|
*.sgm
|
||||||
|
*.iml
|
||||||
|
.idea
|
||||||
|
node_modules
|
12
index.js
Normal file
12
index.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#! /usr/bin/env node
|
||||||
|
const { program } = require('commander')
|
||||||
|
const {applyPatch} = require('./js/cmd')
|
||||||
|
program
|
||||||
|
.command('patch')
|
||||||
|
.description('List all the TODO tasks')
|
||||||
|
.argument('<file>', 'the patch to apply')
|
||||||
|
.argument('<file>','the rom file getting the patch')
|
||||||
|
.option('-v, --validate-checksum','should validate checksum')
|
||||||
|
.action((patch, romFile, options) => applyPatch(romFile, patch, options));
|
||||||
|
|
||||||
|
program.parse()
|
12
js/File.js
Normal file
12
js/File.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
exports.File = File;
|
||||||
|
|
||||||
|
function File(_path) {
|
||||||
|
this.stat = fs.statSync(_path);
|
||||||
|
this.size = this.stat.size;
|
||||||
|
this.name = path.basename(_path);
|
||||||
|
this.type = this.stat.type;
|
||||||
|
this.data = fs.readFileSync(_path);
|
||||||
|
}
|
|
@ -1,6 +1,11 @@
|
||||||
/* MODDED VERSION OF MarcFile.js v20230202 - Marc Robledo 2014-2023 - http://www.marcrobledo.com/license */
|
/* MODDED VERSION OF MarcFile.js v20230202 - Marc Robledo 2014-2023 - http://www.marcrobledo.com/license */
|
||||||
|
|
||||||
function MarcFile(source, onLoad){
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
exports.MarcFile = MarcFile;
|
||||||
|
// saveAs = (blob,fileName) => fs.writeFileSync(fileName, blob.arrayBuffer())
|
||||||
|
}
|
||||||
|
|
||||||
|
function MarcFile(source, onLoad){
|
||||||
if(typeof source==='object' && source.files) /* get first file only if source is input with multiple files */
|
if(typeof source==='object' && source.files) /* get first file only if source is input with multiple files */
|
||||||
source=source.files[0];
|
source=source.files[0];
|
||||||
|
|
||||||
|
@ -9,27 +14,34 @@ function MarcFile(source, onLoad){
|
||||||
this._lastRead=null;
|
this._lastRead=null;
|
||||||
|
|
||||||
if(typeof source==='object' && source.name && source.size){ /* source is file */
|
if(typeof source==='object' && source.name && source.size){ /* source is file */
|
||||||
if(typeof window.FileReader!=='function')
|
|
||||||
throw new Error('Incompatible Browser');
|
|
||||||
|
|
||||||
this.fileName=source.name;
|
this.fileName=source.name;
|
||||||
this.fileType=source.type;
|
this.fileType=source.type;
|
||||||
this.fileSize=source.size;
|
this.fileSize=source.size;
|
||||||
|
try {
|
||||||
|
if (typeof window.FileReader !== 'function')
|
||||||
|
throw new Error('Incompatible Browser');
|
||||||
|
this._fileReader=new FileReader();
|
||||||
|
this._fileReader.addEventListener('load',function(){
|
||||||
|
this.marcFile._u8array=new Uint8Array(this.result);
|
||||||
|
this.marcFile._dataView=new DataView(this.result);
|
||||||
|
|
||||||
this._fileReader=new FileReader();
|
if(onLoad)
|
||||||
this._fileReader.marcFile=this;
|
onLoad.call();
|
||||||
this._fileReader.addEventListener('load',function(){
|
},false);
|
||||||
this.marcFile._u8array=new Uint8Array(this.result);
|
|
||||||
this.marcFile._dataView=new DataView(this.result);
|
|
||||||
|
|
||||||
if(onLoad)
|
|
||||||
onLoad.call();
|
|
||||||
},false);
|
|
||||||
|
|
||||||
this._fileReader.readAsArrayBuffer(source);
|
|
||||||
|
|
||||||
|
|
||||||
|
this._fileReader.marcFile=this;
|
||||||
|
|
||||||
|
this._fileReader.readAsArrayBuffer(source);
|
||||||
|
}catch (e){
|
||||||
|
if(!(e instanceof ReferenceError))
|
||||||
|
throw e;
|
||||||
|
this._fileReader = {}
|
||||||
|
this._u8array = new Uint8Array(source.data.buffer);
|
||||||
|
this._dataView=new DataView(source.data.buffer);
|
||||||
|
this.source = source;
|
||||||
|
MarcFile.prototype.readString = () => source.data.toString();
|
||||||
|
}
|
||||||
}else if(typeof source==='object' && typeof source.fileName==='string' && typeof source.littleEndian==='boolean'){ /* source is MarcFile */
|
}else if(typeof source==='object' && typeof source.fileName==='string' && typeof source.littleEndian==='boolean'){ /* source is MarcFile */
|
||||||
this.fileName=source.fileName;
|
this.fileName=source.fileName;
|
||||||
this.fileType=source.fileType;
|
this.fileType=source.fileType;
|
||||||
|
@ -127,22 +139,26 @@ MarcFile.prototype.copyToFile=function(target, offsetSource, len, offsetTarget){
|
||||||
|
|
||||||
|
|
||||||
MarcFile.prototype.save=function(){
|
MarcFile.prototype.save=function(){
|
||||||
var blob;
|
if(typeof module !== "undefined" && module.exports)
|
||||||
try{
|
require('fs').writeFileSync(this.fileName, Buffer.from(this._u8array.buffer));
|
||||||
blob=new Blob([this._u8array],{type:this.fileType});
|
else {
|
||||||
}catch(e){
|
var blob;
|
||||||
//old browser, use BlobBuilder
|
try {
|
||||||
window.BlobBuilder=window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
blob = new Blob([this._u8array], {type: this.fileType});
|
||||||
if(e.name==='InvalidStateError' && window.BlobBuilder){
|
} catch (e) {
|
||||||
var bb=new BlobBuilder();
|
//old browser, use BlobBuilder
|
||||||
bb.append(this._u8array.buffer);
|
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
|
||||||
blob=bb.getBlob(this.fileType);
|
if (e.name === 'InvalidStateError' && window.BlobBuilder) {
|
||||||
}else{
|
var bb = new BlobBuilder();
|
||||||
throw new Error('Incompatible Browser');
|
bb.append(this._u8array.buffer);
|
||||||
return false;
|
blob = bb.getBlob(this.fileType);
|
||||||
|
} else {
|
||||||
|
throw new Error('Incompatible Browser');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
saveAs(blob, this.fileName);
|
||||||
}
|
}
|
||||||
saveAs(blob,this.fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
193
js/cmd.js
Normal file
193
js/cmd.js
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
const {MarcFile} = require("./MarcFile");
|
||||||
|
const {File} = require("./File")
|
||||||
|
const {IPS_MAGIC, parseIPSFile} = require("./formats/ips")
|
||||||
|
const {UPS_MAGIC, parseUPSFile} = require("./formats/ups")
|
||||||
|
const {APS_N64_MAGIC, parseAPSFile} = require("./formats/aps_n64")
|
||||||
|
const {APS_GBA_MAGIC, APSGBA} = require("./formats/aps_gba")
|
||||||
|
const {BPS_MAGIC, parseBPSFile} = require("./formats/bps")
|
||||||
|
const {RUP_MAGIC, parseRUPFile} = require("./formats/rup")
|
||||||
|
const {PPF_MAGIC, parsePPFFile} = require("./formats/ppf")
|
||||||
|
const {PMSR_MAGIC, parseMODFile} = require("./formats/pmsr")
|
||||||
|
const {VCDIFF_MAGIC, parseVCDIFF} = require("./formats/vcdiff")
|
||||||
|
const {ZIP_MAGIC, ZIPManager} = require("./formats/zip")
|
||||||
|
const {md5} = require("./crc")
|
||||||
|
|
||||||
|
function hasHeader(romFile){
|
||||||
|
if(romFile.fileSize<=0x600200){
|
||||||
|
if(romFile.fileSize%1024===0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(var i=0; i<HEADERS_INFO.length; i++){
|
||||||
|
if(HEADERS_INFO[i][0].test(romFile.fileName) && (romFile.fileSize-HEADERS_INFO[i][1])%HEADERS_INFO[i][1]===0){
|
||||||
|
return HEADERS_INFO[i][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
function validateSource(patch, romFile){
|
||||||
|
if(patch && romFile && typeof patch.validateSource !== 'undefined'){
|
||||||
|
if(patch.validateSource(romFile, hasHeader(romFile))){
|
||||||
|
console.log('apply');
|
||||||
|
}else{
|
||||||
|
console.warn('apply'+ 'error_crc_input'+ 'warning');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
console.log('valid source');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function _readPatchFile(patchFile, romFile){
|
||||||
|
patchFile.littleEndian=false;
|
||||||
|
let patch;
|
||||||
|
const header = patchFile.readString(6);
|
||||||
|
if(patchFile.getExtension()!=='jar' && header.startsWith(ZIP_MAGIC)){
|
||||||
|
patch=false;
|
||||||
|
validateSource();
|
||||||
|
ZIPManager.parseFile(patchFile);
|
||||||
|
}else{
|
||||||
|
if(header.startsWith(IPS_MAGIC)){
|
||||||
|
patch=parseIPSFile(patchFile);
|
||||||
|
}else if(header.startsWith(UPS_MAGIC)){
|
||||||
|
patch=parseUPSFile(patchFile);
|
||||||
|
}else if(header.startsWith(APS_N64_MAGIC)){
|
||||||
|
patch=parseAPSFile(patchFile);
|
||||||
|
}else if(header.startsWith(APS_GBA_MAGIC)){
|
||||||
|
patch=APSGBA.fromFile(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{
|
||||||
|
patch=null;
|
||||||
|
console.log('apply'+ 'error_invalid_patch'+ 'error');
|
||||||
|
}
|
||||||
|
|
||||||
|
validateSource(patchFile, romFile);
|
||||||
|
}
|
||||||
|
return patch;
|
||||||
|
}
|
||||||
|
function preparePatchedRom(originalRom, patchedRom, headerSize) {
|
||||||
|
patchedRom.fileName = originalRom.fileName.replace(/\.([^\.]*?)$/, ' (patched).$1');
|
||||||
|
patchedRom.fileType = originalRom.fileType;
|
||||||
|
if (headerSize) {
|
||||||
|
if (el('checkbox-removeheader').checked) {
|
||||||
|
const patchedRomWithOldHeader = new MarcFile(headerSize + patchedRom.fileSize);
|
||||||
|
oldHeader.copyToFile(patchedRomWithOldHeader, 0);
|
||||||
|
patchedRom.copyToFile(patchedRomWithOldHeader, 0, patchedRom.fileSize, headerSize);
|
||||||
|
patchedRomWithOldHeader.fileName = patchedRom.fileName;
|
||||||
|
patchedRomWithOldHeader.fileType = patchedRom.fileType;
|
||||||
|
patchedRom = patchedRomWithOldHeader;
|
||||||
|
} else if (el('checkbox-addheader').checked) {
|
||||||
|
patchedRom = patchedRom.slice(headerSize);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* fix checksum if needed */
|
||||||
|
// if (false) {
|
||||||
|
// var checksumInfo = _getHeaderChecksumInfo(patchedRom);
|
||||||
|
// if (checksumInfo && checksumInfo.current !== checksumInfo.calculated && confirm(_('fix_checksum_prompt') + ' (' + padZeroes(checksumInfo.current) + ' -> ' + padZeroes(checksumInfo.calculated) + ')')) {
|
||||||
|
// checksumInfo.fix(patchedRom);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
console.log('apply');
|
||||||
|
patchedRom.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function padZeroes(intVal, nBytes){
|
||||||
|
var hexString=intVal.toString(16);
|
||||||
|
while(hexString.length<nBytes*2)
|
||||||
|
hexString='0'+hexString;
|
||||||
|
return hexString
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRC32 - from Alex - https://stackoverflow.com/a/18639999 */
|
||||||
|
const CRC32_TABLE=(function(){
|
||||||
|
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(marcFile, headerSize, ignoreLast4Bytes){
|
||||||
|
var data=headerSize? new Uint8Array(marcFile._u8array.buffer, headerSize):marcFile._u8array;
|
||||||
|
|
||||||
|
var crc=0^(-1);
|
||||||
|
|
||||||
|
var len=ignoreLast4Bytes?data.length-4:data.length;
|
||||||
|
for(var i=0;i<len;i++)
|
||||||
|
crc=(crc>>>8)^CRC32_TABLE[(crc^data[i])&0xff];
|
||||||
|
|
||||||
|
return ((crc^(-1))>>>0);
|
||||||
|
}
|
||||||
|
function updateChecksums(file, romFile, startOffset, force){
|
||||||
|
if(file===romFile && file.fileSize>33554432 && !force){
|
||||||
|
console.log('File is too big. Force calculate checksum? Add -f to command');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('crc32='+padZeroes(crc32(file, startOffset), 4));
|
||||||
|
console.log('md5='+padZeroes(md5(file, startOffset), 16));
|
||||||
|
}
|
||||||
|
let headerSize;
|
||||||
|
|
||||||
|
function canHaveFakeHeader(romFile){
|
||||||
|
if(romFile.fileSize<=0x600000){
|
||||||
|
for(let i=0; i<HEADERS_INFO.length; i++){
|
||||||
|
if(HEADERS_INFO[i][0].test(romFile.fileName) && (romFile.fileSize%HEADERS_INFO[i][2]===0)){
|
||||||
|
return HEADERS_INFO[i][1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
function _parseROM(romFile){
|
||||||
|
if(romFile.getExtension()!=='jar' && romFile.readString(4).startsWith(ZIP_MAGIC)){
|
||||||
|
ZIPManager.parseFile(romFile);
|
||||||
|
}else{
|
||||||
|
if(headerSize=canHaveFakeHeader(romFile)){
|
||||||
|
if(headerSize<1024){
|
||||||
|
console.log(headerSize+'b');
|
||||||
|
}else{
|
||||||
|
console.log(parseInt(headerSize/1024)+'kb');
|
||||||
|
}
|
||||||
|
}else if(headerSize=hasHeader(romFile)){
|
||||||
|
// do nothing
|
||||||
|
}else{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
updateChecksums(romFile, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const applyPatch = (patch, rom, validateChecksums) => {
|
||||||
|
rom = new MarcFile(new File(rom));
|
||||||
|
_parseROM(rom);
|
||||||
|
patch = new MarcFile(new File(patch));
|
||||||
|
patch = _readPatchFile(patch, rom);
|
||||||
|
if (!patch || !rom)
|
||||||
|
throw new Error('No ROM/patch selected');
|
||||||
|
console.log('apply'+ 'applying_patch'+ 'loading');
|
||||||
|
|
||||||
|
try {
|
||||||
|
preparePatchedRom(rom, patch.apply(rom, validateChecksums), headerSize);
|
||||||
|
} catch (e) {
|
||||||
|
// console.log('apply'+ 'Error: ' + (e.message)+ 'error');
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = {applyPatch}
|
|
@ -124,3 +124,7 @@ function crc16(marcFile, offset, len){
|
||||||
|
|
||||||
return crc & 0xffff;
|
return crc & 0xffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {md5};
|
||||||
|
}
|
|
@ -4,7 +4,9 @@
|
||||||
const APS_GBA_MAGIC='APS1';
|
const APS_GBA_MAGIC='APS1';
|
||||||
const APS_GBA_BLOCK_SIZE=0x010000; //64Kb
|
const APS_GBA_BLOCK_SIZE=0x010000; //64Kb
|
||||||
const APS_GBA_RECORD_SIZE=4 + 2 + 2 + APS_GBA_BLOCK_SIZE;
|
const APS_GBA_RECORD_SIZE=4 + 2 + 2 + APS_GBA_BLOCK_SIZE;
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {APS_GBA_MAGIC, APSGBA};
|
||||||
|
}
|
||||||
function APSGBA(){
|
function APSGBA(){
|
||||||
this.sourceSize=0;
|
this.sourceSize=0;
|
||||||
this.targetSize=0;
|
this.targetSize=0;
|
||||||
|
|
|
@ -5,7 +5,9 @@ const APS_N64_MAGIC='APS10';
|
||||||
const APS_RECORD_RLE=0x0000;
|
const APS_RECORD_RLE=0x0000;
|
||||||
const APS_RECORD_SIMPLE=0x01;
|
const APS_RECORD_SIMPLE=0x01;
|
||||||
const APS_N64_MODE=0x01;
|
const APS_N64_MODE=0x01;
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {APS_N64_MAGIC, parseAPSFile};
|
||||||
|
}
|
||||||
function APS(){
|
function APS(){
|
||||||
this.records=[];
|
this.records=[];
|
||||||
this.headerType=0;
|
this.headerType=0;
|
||||||
|
|
|
@ -6,7 +6,9 @@ const BPS_ACTION_SOURCE_READ=0;
|
||||||
const BPS_ACTION_TARGET_READ=1;
|
const BPS_ACTION_TARGET_READ=1;
|
||||||
const BPS_ACTION_SOURCE_COPY=2;
|
const BPS_ACTION_SOURCE_COPY=2;
|
||||||
const BPS_ACTION_TARGET_COPY=3;
|
const BPS_ACTION_TARGET_COPY=3;
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {BPS_MAGIC, parseBPSFile};
|
||||||
|
}
|
||||||
|
|
||||||
function BPS(){
|
function BPS(){
|
||||||
this.sourceSize=0;
|
this.sourceSize=0;
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
/* IPS module for Rom Patcher JS v20220417 - Marc Robledo 2016-2022 - http://www.marcrobledo.com/license */
|
/* IPS module for Rom Patcher JS v20220417 - Marc Robledo 2016-2022 - 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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const IPS_MAGIC='PATCH';
|
const IPS_MAGIC='PATCH';
|
||||||
const IPS_MAX_SIZE=0x1000000; //16 megabytes
|
const IPS_MAX_SIZE=0x1000000; //16 megabytes
|
||||||
const IPS_RECORD_RLE=0x0000;
|
const IPS_RECORD_RLE=0x0000;
|
||||||
const IPS_RECORD_SIMPLE=0x01;
|
const IPS_RECORD_SIMPLE=0x01;
|
||||||
|
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {IPS_MAGIC, IPS_MAX_SIZE, IPS_RECORD_RLE, IPS_RECORD_SIMPLE, IPS, parseIPSFile};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function IPS(){
|
function IPS(){
|
||||||
this.records=[];
|
this.records=[];
|
||||||
this.truncate=false;
|
this.truncate=false;
|
||||||
|
|
|
@ -5,7 +5,9 @@ const PMSR_MAGIC='PMSR';
|
||||||
const YAY0_MAGIC='Yay0';
|
const YAY0_MAGIC='Yay0';
|
||||||
const PAPER_MARIO_USA10_CRC32=0xa7f5cd7e;
|
const PAPER_MARIO_USA10_CRC32=0xa7f5cd7e;
|
||||||
const PAPER_MARIO_USA10_FILE_SIZE=41943040;
|
const PAPER_MARIO_USA10_FILE_SIZE=41943040;
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {PMSR_MAGIC, parseMODFile};
|
||||||
|
}
|
||||||
|
|
||||||
function PMSR(){
|
function PMSR(){
|
||||||
this.targetSize=0;
|
this.targetSize=0;
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
/* File format specification: https://www.romhacking.net/utilities/353/ */
|
/* File format specification: https://www.romhacking.net/utilities/353/ */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const PPF_MAGIC='PPF';
|
const PPF_MAGIC='PPF';
|
||||||
const PPF_IMAGETYPE_BIN=0x00;
|
const PPF_IMAGETYPE_BIN=0x00;
|
||||||
const PPF_IMAGETYPE_GI=0x01;
|
const PPF_IMAGETYPE_GI=0x01;
|
||||||
const PPF_BEGIN_FILE_ID_DIZ_MAGIC='@BEG';//@BEGIN_FILE_ID.DIZ
|
const PPF_BEGIN_FILE_ID_DIZ_MAGIC='@BEG';//@BEGIN_FILE_ID.DIZ
|
||||||
|
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {PPF_MAGIC, parsePPFFile};
|
||||||
|
}
|
||||||
function PPF(){
|
function PPF(){
|
||||||
this.version=3;
|
this.version=3;
|
||||||
this.imageType=PPF_IMAGETYPE_BIN;
|
this.imageType=PPF_IMAGETYPE_BIN;
|
||||||
|
|
|
@ -6,7 +6,9 @@ const RUP_COMMAND_END=0x00;
|
||||||
const RUP_COMMAND_OPEN_NEW_FILE=0x01;
|
const RUP_COMMAND_OPEN_NEW_FILE=0x01;
|
||||||
const RUP_COMMAND_XOR_RECORD=0x02;
|
const RUP_COMMAND_XOR_RECORD=0x02;
|
||||||
const RUP_ROM_TYPES=['raw','nes','fds','snes','n64','gb','sms','mega','pce','lynx'];
|
const RUP_ROM_TYPES=['raw','nes','fds','snes','n64','gb','sms','mega','pce','lynx'];
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {RUP_MAGIC, parseRUPFile};
|
||||||
|
}
|
||||||
|
|
||||||
function RUP(){
|
function RUP(){
|
||||||
this.author='';
|
this.author='';
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
/* File format specification: http://www.romhacking.net/documents/392/ */
|
/* File format specification: http://www.romhacking.net/documents/392/ */
|
||||||
|
|
||||||
const UPS_MAGIC='UPS1';
|
const UPS_MAGIC='UPS1';
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {UPS_MAGIC, UPS, parseUPSFile};
|
||||||
|
}
|
||||||
function UPS(){
|
function UPS(){
|
||||||
this.records=[];
|
this.records=[];
|
||||||
this.sizeInput=0;
|
this.sizeInput=0;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
some code and ideas borrowed from:
|
some code and ideas borrowed from:
|
||||||
https://hack64.net/jscripts/libpatch.js?6
|
https://hack64.net/jscripts/libpatch.js?6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//const VCDIFF_MAGIC=0xd6c3c400;
|
//const VCDIFF_MAGIC=0xd6c3c400;
|
||||||
const VCDIFF_MAGIC='\xd6\xc3\xc4';
|
const VCDIFF_MAGIC='\xd6\xc3\xc4';
|
||||||
/*
|
/*
|
||||||
|
@ -17,7 +16,10 @@ const XDELTA_100_MAGIC='%XDZ002';
|
||||||
const XDELTA_104_MAGIC='%XDZ003';
|
const XDELTA_104_MAGIC='%XDZ003';
|
||||||
const XDELTA_110_MAGIC='%XDZ004';
|
const XDELTA_110_MAGIC='%XDZ004';
|
||||||
*/
|
*/
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {VCDIFF_MAGIC, parseVCDIFF};
|
||||||
|
MarcFile = require("../MarcFile").MarcFile;
|
||||||
|
}
|
||||||
|
|
||||||
function VCDIFF(patchFile){
|
function VCDIFF(patchFile){
|
||||||
this.file=patchFile;
|
this.file=patchFile;
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
const ZIP_MAGIC='\x50\x4b\x03\x04';
|
const ZIP_MAGIC='\x50\x4b\x03\x04';
|
||||||
|
|
||||||
|
if(typeof module !== "undefined" && module.exports){
|
||||||
|
module.exports = {ZIP_MAGIC, ZIPManager};
|
||||||
|
}
|
||||||
var ZIPManager=(function(){
|
var ZIPManager=(function(){
|
||||||
const FILTER_PATCHES=/\.(ips|ups|bps|aps|rup|ppf|mod|xdelta|vcdiff)$/i;
|
const FILTER_PATCHES=/\.(ips|ups|bps|aps|rup|ppf|mod|xdelta|vcdiff)$/i;
|
||||||
//const FILTER_ROMS=/(?<!\.(txt|diz|rtf|docx?|xlsx?|html?|pdf|jpe?g|gif|png|bmp|webp|zip|rar|7z))$/i; //negative lookbehind is not compatible with Safari https://stackoverflow.com/a/51568859
|
//const FILTER_ROMS=/(?<!\.(txt|diz|rtf|docx?|xlsx?|html?|pdf|jpe?g|gif|png|bmp|webp|zip|rar|7z))$/i; //negative lookbehind is not compatible with Safari https://stackoverflow.com/a/51568859
|
||||||
|
|
234
package-lock.json
generated
Normal file
234
package-lock.json
generated
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
{
|
||||||
|
"name": "RomPatcher.js",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^5.2.0",
|
||||||
|
"commander": "^11.0.0",
|
||||||
|
"conf": "^11.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv": {
|
||||||
|
"version": "8.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
|
||||||
|
"integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2",
|
||||||
|
"uri-js": "^4.2.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv-formats": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ajv": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/atomically": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/atomically/-/atomically-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-sxBhVZUFBFhqSAsYMM3X2oaUi2NVDJ8U026FsIusM8gYXls9AYs/eXzgGrufs1Qjpkxi9zunds+75QUFz+m7UQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"stubborn-fs": "^1.2.4",
|
||||||
|
"when-exit": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/chalk": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "11.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-11.0.0.tgz",
|
||||||
|
"integrity": "sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/conf": {
|
||||||
|
"version": "11.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/conf/-/conf-11.0.1.tgz",
|
||||||
|
"integrity": "sha512-WlLiQboEjKx0bYx2IIRGedBgNjLAxtwPaCSnsjWPST5xR0DB4q8lcsO/bEH9ZRYNcj63Y9vj/JG/5Fg6uWzI0Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.12.0",
|
||||||
|
"ajv-formats": "^2.1.1",
|
||||||
|
"atomically": "^2.0.0",
|
||||||
|
"debounce-fn": "^5.1.2",
|
||||||
|
"dot-prop": "^7.2.0",
|
||||||
|
"env-paths": "^3.0.0",
|
||||||
|
"json-schema-typed": "^8.0.1",
|
||||||
|
"semver": "^7.3.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/debounce-fn": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Sr4SdOZ4vw6eQDvPYNxHogvrxmCIld/VenC5JbNrFwMiwd7lY/Z18ZFfo+EWNG4DD9nFlAujWAo/wGuOPHmy5A==",
|
||||||
|
"dependencies": {
|
||||||
|
"mimic-fn": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/dot-prop": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA==",
|
||||||
|
"dependencies": {
|
||||||
|
"type-fest": "^2.11.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/env-paths": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fast-deep-equal": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
|
},
|
||||||
|
"node_modules/json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||||
|
},
|
||||||
|
"node_modules/json-schema-typed": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg=="
|
||||||
|
},
|
||||||
|
"node_modules/lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mimic-fn": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/punycode": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/require-from-string": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/semver": {
|
||||||
|
"version": "7.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
|
||||||
|
"integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^6.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/stubborn-fs": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-KRa4nIRJ8q6uApQbPwYZVhOof8979fw4xbajBWa5kPJFa4nyY3aFaMWVyIVCDnkNCCG/3HLipUZ4QaNlYsmX1w=="
|
||||||
|
},
|
||||||
|
"node_modules/type-fest": {
|
||||||
|
"version": "2.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||||
|
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/uri-js": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
|
||||||
|
"dependencies": {
|
||||||
|
"punycode": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/when-exit": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-H85ulNwUBU1e6PGxkWUDgxnbohSXD++ah6Xw1VHAN7CtypcbZaC4aYjQ+C2PMVaDkURDuOinNAT+Lnz3utWXxQ=="
|
||||||
|
},
|
||||||
|
"node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
package.json
Normal file
17
package.json
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"chalk": "^5.2.0",
|
||||||
|
"commander": "^11.0.0",
|
||||||
|
"conf": "^11.0.1"
|
||||||
|
},
|
||||||
|
"name": "rompatcher",
|
||||||
|
"description": "A ROM patcher made in HTML5.",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"devDependencies": {},
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue