zelda64
Version:
Zelda64.js is a library that can compress, decompress and patch Nintendo 64 Zelda game ROMs.
1 lines • 16.3 kB
JavaScript
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("pako")):"function"==typeof define&&define.amd?define(["pako"],e):"object"==typeof exports?exports.Zelda64=e(require("pako")):t.Zelda64=e(t.pako)}(self,(t=>(()=>{"use strict";var e={304:function(t,e,r){var i=this&&this.__createBinding||(Object.create?function(t,e,r,i){void 0===i&&(i=r),Object.defineProperty(t,i,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,i){void 0===i&&(i=r),t[i]=e[r]}),s=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),n=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)"default"!==r&&Object.prototype.hasOwnProperty.call(t,r)&&i(e,t,r);return s(e,t),e};Object.defineProperty(e,"__esModule",{value:!0}),e.Operation=void 0;const a=n(r(216)),o=r(882),c=r(749),_=r(902);var u;!function(t){t[t.COPY=0]="COPY",t[t.COMPRESS=1]="COMPRESS",t[t.NULL=2]="NULL"}(u=e.Operation||(e.Operation={}));class h{constructor(t,e=[]){this._buffer=t,this._in=new a.default(this._buffer),this._ops=new Uint16Array(this._in.dmaCount).fill(u.COMPRESS,3),this._checkExclusions(e)}_checkExclusions(t){const e=this._in.dmaCount-1;for(let r=0;r<t.length;r++){const i=t[r];i>e||i<-e?console.log(`Exclusion index ${i} is out of bounds`):i<0?this._ops[1+~i]=u.NULL:this._ops[i]=u.COPY}}deflate(){const t=new ArrayBuffer(a.COMPRESSED_ROM_SIZE),e=new o.Writer(t),r=this._in.dmaCount-3,i=new Uint8Array(this._buffer,0,this._in.dmaOffset+this._in.dmaSize);new Uint8Array(t).set(i);let s=this._in.dmaOffset+this._in.dmaSize;for(let t=a.DMA_INFO_RECORD_INDEX+1;t<this._in.dmaCount;t++){const i=this._in.readDmaRecord(t),n=i.virtualEnd-i.virtualStart,a=new Uint8Array(this._buffer,i.virtualStart,n),o={op:u.NULL,data:new Uint8Array,size:0};switch(this._ops[t]){case u.COPY:this._progressFn(t-2,r,u.COPY,a.byteLength),o.op=u.COPY,o.data=a,o.size=a.byteLength;break;case u.COMPRESS:const e=h._compress(a);this._progressFn(t-2,r,u.COMPRESS,a.byteLength,e.byteLength),o.op=u.COMPRESS,o.data=e,o.size=e.byteLength;break;case u.NULL:this._progressFn(t-2,r,u.NULL),o.op=u.NULL,o.data=void 0,o.size=0;break;default:throw new Error("invalid operation")}if(i.virtualStart!=i.virtualEnd){i.physicalStart=s,o.op===u.COMPRESS?i.physicalEnd=i.physicalStart+o.size:o.op===u.NULL&&(i.physicalStart=4294967295,i.physicalEnd=4294967295);try{4294967295!==i.physicalStart&&e.writeBytes(o.data,i.physicalStart),this._writeDmaRecord(e,t,i)}catch(t){break}}s+=o.size}return new _.N64Crc(t).recalculate(),t}static _compress(t){return new c.Yaz0Compressor(t).result}_writeDmaRecord(t,e,r){t.seek(this._in.dmaOffset,"begin"),t.seek(e*a.DMA_RECORD_SIZE),t.writeUint32(r.virtualStart),t.writeUint32(r.virtualEnd),t.writeUint32(r.physicalStart),t.writeUint32(r.physicalEnd)}set onprogress(t){this._progressFn=t}}e.default=h},902:(t,e,r)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.N64Crc=void 0;const i=r(882);class s{constructor(t){this._buffer=t,this._reader=new i.Reader(this._buffer),this._data=new Uint8Array(this._buffer)}recalculate(){s._generateTable();const t=this._calculate(),e=new Uint8Array(4),r=new Uint8Array(4);for(let i=0;i<4;i++)e[i]=t[0]>>>24-8*i&255,r[i]=t[1]>>>24-8*i&255;this._data.set(e,16),this._data.set(r,20)}_calculate(){const t=this._cic(),e=s._seed(t);let r=e,n=e,a=e,o=e,c=e,_=e;for(let e=4096;e<1052672;e+=4){const s=this._reader.readUint32(e);(0,i.u32)(_+s)<_&&o++,_=(0,i.u32)(_+s),a=(0,i.u32)(a^s);const f=(0,i.u32)((u=s)<<(h=31&s)|u>>>32-h);if(c=(0,i.u32)(c+f),n=n>s?(0,i.u32)(n^f):(0,i.u32)(n^_^s),6105===t){const t=1872+(255&e),n=this._reader.readUint32(t);r=(0,i.u32)(r+(n^s))}else r=(0,i.u32)(r+(c^s))}var u,h;return 6103===t?[(_^o)+a,(c^n)+r]:6106===t?[_*o+a,c*n+r]:[_^o^a,c^n^r]}static _seed(t){switch(t){case 6101:case 6102:return 4174007772;case 6103:return 2743625561;case 6105:return 3743872054;case 6106:return 535454074}}_cic(){switch(s._crc32(new Uint8Array(this._buffer,64,4032))){case 1634772129:return 6101;case 2428202165:return 6102;case 184880864:return 6103;case 2562468998:return 6105;case 2898810890:return 6106}throw new Error("could not calculate CIC")}static _generateTable(){if(void 0===this._table){this._table=new Uint32Array(256);for(let t=0;t<this._table.length;t++){let e=t;for(let r=8;r>0;r--)1&e?e=e>>>1^3988292384:e>>>=1,this._table[t]=e}}}static _crc32(t){if(void 0===this._table)throw new Error("CRC table is undefined");let e=-1;for(let r=0;r<t.length;r++){const i=255&(e^t[r]);e=e>>>8^this._table[i]}return~e>>>0}}e.N64Crc=s},134:function(t,e,r){var i=this&&this.__createBinding||(Object.create?function(t,e,r,i){void 0===i&&(i=r),Object.defineProperty(t,i,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,i){void 0===i&&(i=r),t[i]=e[r]}),s=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),n=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)"default"!==r&&Object.prototype.hasOwnProperty.call(t,r)&&i(e,t,r);return s(e,t),e};Object.defineProperty(e,"__esModule",{value:!0});const a=r(882),o=n(r(216)),c=r(902);class _{constructor(t){this._buffer=t,this._in=new o.default(this._buffer)}_writeDmaRecord(t,e,r){t.seek(this._in.dmaOffset,"begin"),t.seek(e*o.DMA_RECORD_SIZE),t.writeUint32(r.virtualStart),t.writeUint32(r.virtualEnd),t.writeUint32(r.physicalStart),t.writeUint32(r.physicalEnd)}inflate(){const t=this._in.readDmaRecord(o.DMA_INFO_RECORD_INDEX),e=[],r=new ArrayBuffer(o.DECOMPRESSED_ROM_SIZE),i=new a.Writer(r);i.writeBytes(this._buffer),i.fill(0,o.DECOMPRESSED_ROM_SIZE-t.virtualEnd,t.virtualEnd);for(let t=o.DMA_INFO_RECORD_INDEX+1;t<this._in.dmaCount;t++){const s=this._in.readDmaRecord(t),n=s.virtualEnd-s.virtualStart;if(!(s.physicalStart>=o.DECOMPRESSED_ROM_SIZE||4294967295===s.physicalEnd)){if(0===s.physicalEnd)e.push(t),i.writeBytes(this._in.readBytes(n,s.physicalStart),s.virtualStart,n);else{const t=new Uint8Array(this._buffer,s.physicalStart+16),e=new Uint8Array(r,s.virtualStart);_._decompress(t,e,n)}s.physicalStart=s.virtualStart,s.physicalEnd=0,this._writeDmaRecord(i,t,s)}}return new c.N64Crc(r).recalculate(),{data:r,exclusions:e}}static _decompress(t,e,r){let i=0,s=0,n=0,a=0;for(;s<r;){if(0===a&&(n=t[i++],a=8),128&n)e[s++]=t[i++];else{let r=t[i++],n=s-(1+((15&r)<<8|t[i++])),a=r>>>4;0===a?a=t[i++]+18:a+=2;for(let t=0;t<a;t++)e[s++]=e[n++]}n<<=1,a--}}}e.default=_},607:function(t,e,r){var i=this&&this.__createBinding||(Object.create?function(t,e,r,i){void 0===i&&(i=r),Object.defineProperty(t,i,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,i){void 0===i&&(i=r),t[i]=e[r]}),s=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),n=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)"default"!==r&&Object.prototype.hasOwnProperty.call(t,r)&&i(e,t,r);return s(e,t),e},a=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}};Object.defineProperty(e,"__esModule",{value:!0});const o=n(r(304)),c=a(r(134)),_=a(r(91)),u={Rom:a(r(216)).default,Compressor:o.default,Decompressor:c.default,Patcher:_.default,Operation:o.Operation};e.default=u},91:function(t,e,r){var i=this&&this.__createBinding||(Object.create?function(t,e,r,i){void 0===i&&(i=r),Object.defineProperty(t,i,{enumerable:!0,get:function(){return e[r]}})}:function(t,e,r,i){void 0===i&&(i=r),t[i]=e[r]}),s=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),n=this&&this.__importStar||function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var r in t)"default"!==r&&Object.prototype.hasOwnProperty.call(t,r)&&i(e,t,r);return s(e,t),e};Object.defineProperty(e,"__esModule",{value:!0});const a=n(r(366)),o=r(882),c=n(r(216)),_=r(902);e.default=class{constructor(t){if(this._patchData=a.inflate(new Uint8Array(t)).buffer,this._patchView=new DataView(this._patchData),!this._validateHeader())throw new Error("not a valid ZPF file");this._conf=this._readPatchConfiguration()}patch(t){const e=new c.default(t),r=new ArrayBuffer(t.byteLength);new Uint8Array(r).set(new Uint8Array(t));const i=new o.Reader(this._patchData),s=new o.Writer(r);return this._updateDmaTable(i,s,e),this._patchDataBlocks(i,s,e),new _.N64Crc(r).recalculate(),r}_validateHeader(){return"ZPFv1"===(new TextDecoder).decode(this._patchData.slice(0,5))}_readPatchConfiguration(){return{dmaOffset:this._patchView.getUint32(5),xorRange:[this._patchView.getUint32(9),this._patchView.getUint32(13)],xorAddress:this._patchView.getUint32(17)}}_updateDmaTable(t,e,r){for(t.seek(21,"begin");;){const i=t.readUint16();if(65535===i)break;const s=t.readUint32(),n=t.readUint32(),a=t.readUint24();if(this._writeDmaRecord(e,i,{virtualStart:n,virtualEnd:n+a,physicalStart:n,physicalEnd:0}),4294967295!==s){const t=r.readDmaRecordByKey(s),i=a<t.physicalStart?a:t.physicalStart;e.writeBytes(r.readBytes(i,s),n),e.fill(0,a-i,n+i)}else e.fill(0,a,n)}}_writeDmaRecord(t,e,r){t.seek(this._conf.dmaOffset,"begin"),t.seek(e*c.DMA_RECORD_SIZE),t.writeUint32(r.virtualStart),t.writeUint32(r.virtualEnd),t.writeUint32(r.physicalStart),t.writeUint32(r.physicalEnd)}_patchDataBlocks(t,e,r){let i=0,s=this._conf.xorAddress;for(;!t.eof();){let n=0;if(255!==t.readUint8())t.seek(-1),i=t.readUint32(),n=t.readUint16();else{const e=t.readUint8();n=t.readUint16();for(let t=0;t<e;t++)s=this._getNextXorKey(r,s,this._conf.xorRange).address}const a=new Uint8Array(t.readBytes(n)),o=new Uint8Array(new ArrayBuffer(n));for(let t=0;t<n;t++)if(0===a[t])o[t]=0;else{const e=this._getNextXorKey(r,s,this._conf.xorRange);s=e.address,o[t]=a[t]^e.key}e.writeBytes(o.buffer,i),i+=n}}_getNextXorKey(t,e,r){let i=0;for(;0===i;)(e+=1)>r[1]&&(e=r[0]),i=t.readUint8(e);return{key:i,address:e}}}},216:(t,e,r)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.RomType=e.DMA_INFO_RECORD_INDEX=e.DECOMPRESSED_ROM_SIZE=e.COMPRESSED_ROM_SIZE=e.DMA_RECORD_SIZE=e.CRC_SIZE=e.CRC_OFFSET=void 0;const i=r(882);var s;e.CRC_OFFSET=16,e.CRC_SIZE=8,e.DMA_RECORD_SIZE=16,e.COMPRESSED_ROM_SIZE=33554432,e.DECOMPRESSED_ROM_SIZE=67108864,e.DMA_INFO_RECORD_INDEX=2,function(t){t[t.COMPRESSED=0]="COMPRESSED",t[t.BIG_ENDIAN_COMPRESSED=1]="BIG_ENDIAN_COMPRESSED",t[t.DECOMPRESSED=2]="DECOMPRESSED",t[t.INVALID=3]="INVALID"}(s=e.RomType||(e.RomType={}));const n={[s.COMPRESSED]:[236,112,17,183,118,22,215,43],[s.BIG_ENDIAN_COMPRESSED]:[112,236,183,17,22,118,43,215],[s.DECOMPRESSED]:[147,82,46,123,229,6,212,39]};class a extends i.Reader{constructor(t){super(t),this._type=this._findRomType(),this._type===s.BIG_ENDIAN_COMPRESSED&&(console.log("ROM is big endian, correcting endianness..."),this._fixEndianness()),this._dmaOffset=this._findDmaTableOffset();const r=this.readDmaRecord(e.DMA_INFO_RECORD_INDEX);this._dmaSize=r.virtualEnd-r.virtualStart,this._dmaCount=this._dmaSize/e.DMA_RECORD_SIZE}_findRomType(){const t=new Uint8Array(this._buffer,e.CRC_OFFSET,e.CRC_SIZE);return t.every(((t,e)=>t===n[s.COMPRESSED][e]))?s.COMPRESSED:t.every(((t,e)=>t===n[s.BIG_ENDIAN_COMPRESSED][e]))?s.BIG_ENDIAN_COMPRESSED:t.every(((t,e)=>t===n[s.DECOMPRESSED][e]))?s.DECOMPRESSED:s.INVALID}_fixEndianness(){const t=new Uint16Array(this._buffer);for(let r=0;r<e.COMPRESSED_ROM_SIZE/2;r++)t[r]=(0,i.swap16)(t[r])}_findDmaTableOffset(){const t=new Uint32Array(this._buffer);for(let e=1048;e+4<16777216;e+=4)if(0===t[e]&&1611661312===t[e+1])return 4*e;throw new Error("no DMA table found")}readDmaRecord(t){if(t>=this._dmaCount)throw new Error("DMA record index is out of bounds");return this.seek(this._dmaOffset,"begin"),this.seek(16*t),{virtualStart:this.readUint32(),virtualEnd:this.readUint32(),physicalStart:this.readUint32(),physicalEnd:this.readUint32()}}readDmaRecordByKey(t){for(let e=0;e<this._dmaCount;e++){let r=this.readDmaRecord(e);if(0===r.virtualStart&&0===r.virtualEnd)return;if(r.virtualStart===t)return r}}get dmaOffset(){return this._dmaOffset}get dmaCount(){return this._dmaCount}get dmaSize(){return this._dmaSize}get type(){return this._type}get bigEndian(){return this._type===s.BIG_ENDIAN_COMPRESSED}}e.default=a},882:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.Writer=e.Reader=e.u32=e.parse32=e.swap16=e.swap32=void 0,e.swap32=function(t){return(255&t)<<24|(65280&t)<<8|(16711680&t)>>>8|(4278190080&t)>>>24},e.swap16=function(t){return(255&t)<<8|(65280&t)>>>8},e.parse32=function(t,e){return t[e]<<24|t[e+1]<<16|t[e+2]<<8|t[e+3]},e.u32=function(t){return(4294967295&t)>>>0};class r{constructor(t){this._buffer=t,this._view=new DataView(this._buffer),this._cursor=0}seek(t,e="current"){const r=this._cursor;switch(e){case"begin":this._cursor=t;break;case"current":this._cursor+=t;break;case"end":this._cursor=this._buffer.byteLength+t}return r}eof(){return this._cursor>=this._buffer.byteLength}}e.Reader=class extends r{constructor(t){super(t)}readUint8(t){if(void 0!==t)return this._view.getUint8(t);{const t=this._view.getUint8(this._cursor);return this._cursor+=1,t}}readUint16(t){if(void 0!==t)return this._view.getUint16(t);{const t=this._view.getUint16(this._cursor);return this._cursor+=2,t}}readUint24(t){const e=void 0!==t?t:this._cursor,r=this._view.getUint16(e),i=this._view.getUint8(e+2);return void 0===t&&(this._cursor+=3),(r<<8)+i}readInt32(t,e){if(void 0!==t)return this._view.getInt32(t,e);{const t=this._view.getInt32(this._cursor,e);return this._cursor+=4,t}}readUint32(t,e){if(void 0!==t)return this._view.getUint32(t,e);{const t=this._view.getUint32(this._cursor,e);return this._cursor+=4,t}}readBytes(t,e){if(void 0!==e)return this._buffer.slice(e,e+t);{const e=this._buffer.slice(this._cursor,this._cursor+t);return this._cursor+=t,e}}},e.Writer=class extends r{constructor(t){super(t)}writeUint32(t,e,r){void 0!==e?this._view.setUint32(e,t,r):(this._view.setUint32(this._cursor,t,r),this._cursor+=4)}writeBytes(t,e,r){const i=new Uint8Array(t),s=void 0!==e?e:this._cursor,n=void 0!==r?r:t.byteLength;let a=0;for(let t=0;t<n;t++)this._view.setUint8(s+t,i[t]),a++;if(a!==n)throw new Error("did not copy all bytes");void 0===e&&(this._cursor+=a)}fill(t,e,r){const i=new ArrayBuffer(e),s=new Uint8Array(t);for(let r=0;r<e;r++)s[r]=t;this.writeBytes(i,r)}}},749:(t,e,r)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.Yaz0Compressor=void 0;const i=r(882);e.Yaz0Compressor=class{constructor(t){this._matchPosition=0,this._match=0,this._srcPos=0,this._size=0,this._flag=0,this._src=t,this._buffer=this._src.buffer,this._reader=new i.Reader(this._buffer),this._srcSize=this._src.byteLength,this._result=this._encode()}_encode(){const t=new ArrayBuffer(this._srcSize+592),e=new i.Writer(t),r=new Uint8Array(t,16);e.writeBytes((new TextEncoder).encode("Yaz0")),e.writeUint32(this._srcSize);let s=0,n=1,a=128,o=0;for(;this._srcPos<this._srcSize;){let t=this._findBest(this._srcPos);if(t<3)r[n++]=this._src[this._srcPos++],o|=a;else if(t>17){const e=this._srcPos-this._matchPosition-1;r[n++]=e>>>8,r[n++]=255&e,t>273&&(t=273),r[n++]=(0,i.u32)(t-18&255),this._srcPos+=t}else{const e=this._srcPos-this._matchPosition-1;r[n++]=t-2<<4|e>>>8,r[n++]=255&e,this._srcPos+=t}a>>>=1,0===a&&(r[s]=o,s=n,this._srcPos<this._srcSize&&n++,o=0,a=128)}return 0!==a&&(r[s]=o),new Uint8Array(t,0,n+31&-16)}_findBest(t){if(1===this._flag)return this._flag=0,this._size;this._flag=0;let e=this._rabinKarp(t);return e>=3&&(this._size=this._rabinKarp(t+1,!0),this._size>=e+2&&(e=1,this._flag=1,this._matchPosition=this._match)),e}_rabinKarp(t,e){let r=this._srcSize-t,s=t-4096;if(r<3)return 0;r>273&&(r=273),s<0&&(s=0);let n=(0,i.parse32)(this._src,t);n>>>=8;let a=(0,i.parse32)(this._src,s);a>>>=8;let o=0,c=0;for(let e=s;e<t;e++){if(a===n){let i=0;for(i=3;i<r&&this._src[e+i]===this._src[t+i];i++);if(i>o&&(o=i,c=e,273===o))break}a=16777215&(a<<8|this._src[e+3])}return!0===e?this._match=c:this._matchPosition=c,o}get result(){return this._result}}},366:e=>{e.exports=t}},r={};return function t(i){var s=r[i];if(void 0!==s)return s.exports;var n=r[i]={exports:{}};return e[i].call(n.exports,n,n.exports,t),n.exports}(607)})()));