@chicowall/grf-loader 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var P=Object.create;var b=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var _=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var L=(t,e)=>{for(var r in e)b(t,r,{get:e[r],enumerable:!0})},w=(t,e,r,x)=>{if(e&&typeof e=="object"||typeof e=="function")for(let f of B(e))!I.call(t,f)&&f!==r&&b(t,f,{get:()=>e[f],enumerable:!(x=R(e,f))||x.enumerable});return t};var z=(t,e,r)=>(r=t!=null?P(_(t)):{},w(e||!t||!t.__esModule?b(r,"default",{value:t,enumerable:!0}):r,t)),D=t=>w(b({},"__esModule",{value:!0}),t);var Q={};L(Q,{GrfBrowser:()=>d,GrfNode:()=>m});module.exports=D(Q);var h=require("pako"),F=z(require("jdataview"),1);var l=new Uint8Array([128,64,32,16,8,4,2,1]),i=new Uint8Array(8),s=new Uint8Array(8),c=new Uint8Array(8),N=new Uint8Array([58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7]),j=new Uint8Array([40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25]),C=new Uint8Array([16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25]),E=[new Uint8Array([239,3,65,253,216,116,30,71,38,239,251,34,179,216,132,30,57,172,167,96,98,193,205,186,92,150,144,89,5,59,122,133,64,253,30,200,231,138,139,33,218,67,100,159,45,20,177,114,245,91,200,182,156,55,118,236,57,160,163,5,82,110,15,217]),new Uint8Array([167,221,13,120,158,11,227,149,96,54,54,79,249,96,90,163,17,36,210,135,200,82,117,236,187,193,76,186,36,254,143,25,218,19,102,175,73,208,144,6,140,106,251,145,55,141,13,120,191,73,17,244,35,229,206,59,85,188,162,87,232,34,116,206]),new Uint8Array([44,234,193,191,74,36,31,194,121,71,162,124,182,217,104,21,128,86,93,1,51,253,244,174,222,48,7,155,229,131,155,104,73,180,46,131,31,194,181,124,162,25,216,229,124,47,131,218,247,107,144,254,196,1,90,151,97,166,61,64,11,88,230,61]),new Uint8Array([77,209,178,15,40,189,228,120,246,74,15,147,139,23,209,164,58,236,201,53,147,86,126,203,85,32,160,254,108,137,23,98,23,98,75,177,180,222,209,135,201,20,60,74,126,168,226,125,160,159,246,92,106,9,141,240,15,227,83,37,149,54,40,203])];function G(t,e){for(let r=0;r<64;++r){let x=N[r]-1;t[e+(x>>3&7)]&l[x&7]&&(i[r>>3&7]|=l[r&7])}t.set(i,e),i.set(c)}function H(t,e){for(let r=0;r<64;++r){let x=j[r]-1;t[e+(x>>3&7)]&l[x&7]&&(i[r>>3&7]|=l[r&7])}t.set(i,e),i.set(c)}function Y(t,e){for(let r=0;r<32;++r){let x=C[r]-1;t[e+(x>>3)]&l[x&7]&&(i[(r>>3)+4]|=l[r&7])}t.set(i,e),i.set(c)}function M(t,e){i[0]=(t[e+7]<<5|t[e+4]>>3)&63,i[1]=(t[e+4]<<1|t[e+5]>>7)&63,i[2]=(t[e+4]<<5|t[e+5]>>3)&63,i[3]=(t[e+5]<<1|t[e+6]>>7)&63,i[4]=(t[e+5]<<5|t[e+6]>>3)&63,i[5]=(t[e+6]<<1|t[e+7]>>7)&63,i[6]=(t[e+6]<<5|t[e+7]>>3)&63,i[7]=(t[e+7]<<1|t[e+4]>>7)&63,t.set(i,e),i.set(c)}function k(t,e){for(let r=0;r<4;++r)i[r]=E[r][t[r*2+0+e]]&240|E[r][t[r*2+1+e]]&15;t.set(i,e),i.set(c)}function O(t,e){for(let r=0;r<8;r++)s[r]=t[e+r];M(s,0),k(s,0),Y(s,0),t[e+0]^=s[4],t[e+1]^=s[5],t[e+2]^=s[6],t[e+3]^=s[7]}function y(t,e){G(t,e),O(t,e),H(t,e)}function v(t,e,r){let x=r.toString().length,f=x<3?1:x<5?x+1:x<7?x+9:x+15,n=e>>3;for(let a=0;a<20&&a<n;++a)y(t,a*8);for(let a=20,o=-1;a<n;++a){if(a%f===0){y(t,a*8);continue}++o&&o%7===0&&$(t,a*8)}}function S(t,e){let r=e>>3;for(let x=0;x<20&&x<r;++x)y(t,x*8)}function $(t,e){i[0]=t[e+3],i[1]=t[e+4],i[2]=t[e+6],i[3]=t[e+0],i[4]=t[e+1],i[5]=t[e+2],i[6]=t[e+5],i[7]=Z[t[e+7]],t.set(i,e),i.set(c)}var Z=(()=>{let t=new Uint8Array([0,43,108,128,1,104,72,119,96,255,185,192,254,235]),e=new Uint8Array(Array.from({length:256},(x,f)=>f)),r=t.length;for(let x=0;x<r;x+=2)e[t[x+0]]=t[x+1],e[t[x+1]]=t[x+0];return e})();var X=1,q=2,J=4,K="Master of Magic",g=46,T=Uint32Array.BYTES_PER_ELEMENT*2,u=class{constructor(e){this.fd=e;this.version=512;this.fileCount=0;this.loaded=!1;this.files=new Map;this.fileTableOffset=0}async getStreamReader(e,r){let x=await this.getStreamBuffer(this.fd,e,r);return new F.default(x,void 0,void 0,!0)}async load(){this.loaded||(await this.parseHeader(),await this.parseFileList(),this.loaded=!0)}async parseHeader(){let e=await this.getStreamReader(0,g);if(e.getString(15)!==K)throw new Error("Not a GRF file (invalid signature)");e.skip(15),this.fileTableOffset=e.getUint32()+g;let x=e.getUint32();if(this.fileCount=e.getUint32()-x-7,this.version=e.getUint32(),this.version!==512)throw new Error(`Unsupported version "0x${this.version.toString(16)}"`)}async parseFileList(){let e=await this.getStreamReader(this.fileTableOffset,T),r=e.getUint32(),x=e.getUint32(),f=await this.getStreamBuffer(this.fd,this.fileTableOffset+T,r),n=(0,h.inflate)(f,{});for(let a=0,o=0;a<this.fileCount;++a){let A="";for(;n[o];)A+=String.fromCharCode(n[o++]);o++;let U={compressedSize:n[o++]|n[o++]<<8|n[o++]<<16|n[o++]<<24,lengthAligned:n[o++]|n[o++]<<8|n[o++]<<16|n[o++]<<24,realSize:n[o++]|n[o++]<<8|n[o++]<<16|n[o++]<<24,type:n[o++],offset:(n[o++]|n[o++]<<8|n[o++]<<16|n[o++]<<24)>>>0};U.type&X&&this.files.set(A,U)}}decodeEntry(e,r){return r.type&q?v(e,r.lengthAligned,r.compressedSize):r.type&J&&S(e,r.lengthAligned),r.realSize===r.compressedSize?e:(0,h.inflate)(e,{})}async getFile(e){if(!this.loaded)return Promise.resolve({data:null,error:"GRF not loaded yet"});let r=e;if(!this.files.has(r))return Promise.resolve({data:null,error:`File "${r}" not found`});let x=this.files.get(r);if(!x)return{data:null,error:`File "${r}" not found`};let f=await this.getStreamBuffer(this.fd,x.offset+g,x.lengthAligned);try{let n=this.decodeEntry(f,x);return Promise.resolve({data:n,error:null})}catch(n){return{data:null,error:n instanceof Error?n.message:String(n)}}}};var d=class extends u{async getStreamBuffer(e,r,x){return new Promise((f,n)=>{let a=new FileReader;a.onerror=n,a.onload=()=>f(new Uint8Array(a.result)),a.readAsArrayBuffer(e.slice(r,r+x))})}};var p=require("fs");var m=class extends u{constructor(e){super(e);try{if(!(0,p.fstatSync)(e).isFile())throw new Error("GRFNode: file descriptor must point to a regular file")}catch{throw new Error("GRFNode: invalid file descriptor")}}async getStreamBuffer(e,r,x){let f=Buffer.allocUnsafe(x);if((0,p.readSync)(e,f,0,x,r)!==x)throw new Error("Not a GRF file (invalid signature)");return f}};0&&(module.exports={GrfBrowser,GrfNode});
1
+ "use strict";var O=Object.create;var h=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var D=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var N=(r,e)=>{for(var t in e)h(r,t,{get:e[t],enumerable:!0})},S=(r,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of C(e))!M.call(r,a)&&a!==t&&h(r,a,{get:()=>e[a],enumerable:!(o=I(e,a))||o.enumerable});return r};var P=(r,e,t)=>(t=r!=null?O(D(r)):{},S(e||!r||!r.__esModule?h(t,"default",{value:r,enumerable:!0}):t,r)),j=r=>S(h({},"__esModule",{value:!0}),r);var oe={};N(oe,{GrfBrowser:()=>p,GrfNode:()=>y,bufferPool:()=>m});module.exports=j(oe);var A=P(require("pako"),1),R=P(require("jdataview"),1);var c=new Uint8Array([128,64,32,16,8,4,2,1]),n=new Uint8Array(8),f=new Uint8Array(8),u=new Uint8Array(8),G=new Uint8Array([58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7]),H=new Uint8Array([40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25]),k=new Uint8Array([16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25]),T=[new Uint8Array([239,3,65,253,216,116,30,71,38,239,251,34,179,216,132,30,57,172,167,96,98,193,205,186,92,150,144,89,5,59,122,133,64,253,30,200,231,138,139,33,218,67,100,159,45,20,177,114,245,91,200,182,156,55,118,236,57,160,163,5,82,110,15,217]),new Uint8Array([167,221,13,120,158,11,227,149,96,54,54,79,249,96,90,163,17,36,210,135,200,82,117,236,187,193,76,186,36,254,143,25,218,19,102,175,73,208,144,6,140,106,251,145,55,141,13,120,191,73,17,244,35,229,206,59,85,188,162,87,232,34,116,206]),new Uint8Array([44,234,193,191,74,36,31,194,121,71,162,124,182,217,104,21,128,86,93,1,51,253,244,174,222,48,7,155,229,131,155,104,73,180,46,131,31,194,181,124,162,25,216,229,124,47,131,218,247,107,144,254,196,1,90,151,97,166,61,64,11,88,230,61]),new Uint8Array([77,209,178,15,40,189,228,120,246,74,15,147,139,23,209,164,58,236,201,53,147,86,126,203,85,32,160,254,108,137,23,98,23,98,75,177,180,222,209,135,201,20,60,74,126,168,226,125,160,159,246,92,106,9,141,240,15,227,83,37,149,54,40,203])];function Y(r,e){for(let t=0;t<64;++t){let o=G[t]-1;r[e+(o>>3&7)]&c[o&7]&&(n[t>>3&7]|=c[t&7])}r.set(n,e),n.set(u)}function $(r,e){for(let t=0;t<64;++t){let o=H[t]-1;r[e+(o>>3&7)]&c[o&7]&&(n[t>>3&7]|=c[t&7])}r.set(n,e),n.set(u)}function q(r,e){for(let t=0;t<32;++t){let o=k[t]-1;r[e+(o>>3)]&c[o&7]&&(n[(t>>3)+4]|=c[t&7])}r.set(n,e),n.set(u)}function Z(r,e){n[0]=(r[e+7]<<5|r[e+4]>>3)&63,n[1]=(r[e+4]<<1|r[e+5]>>7)&63,n[2]=(r[e+4]<<5|r[e+5]>>3)&63,n[3]=(r[e+5]<<1|r[e+6]>>7)&63,n[4]=(r[e+5]<<5|r[e+6]>>3)&63,n[5]=(r[e+6]<<1|r[e+7]>>7)&63,n[6]=(r[e+6]<<5|r[e+7]>>3)&63,n[7]=(r[e+7]<<1|r[e+4]>>7)&63,r.set(n,e),n.set(u)}function X(r,e){for(let t=0;t<4;++t)n[t]=T[t][r[t*2+0+e]]&240|T[t][r[t*2+1+e]]&15;r.set(n,e),n.set(u)}function J(r,e){for(let t=0;t<8;t++)f[t]=r[e+t];Z(f,0),X(f,0),q(f,0),r[e+0]^=f[4],r[e+1]^=f[5],r[e+2]^=f[6],r[e+3]^=f[7]}function U(r,e){Y(r,e),J(r,e),$(r,e)}function F(r,e,t){let o=t.toString().length,a=o<3?1:o<5?o+1:o<7?o+9:o+15,i=e>>3;for(let x=0;x<20&&x<i;++x)U(r,x*8);for(let x=20,l=-1;x<i;++x){if(x%a===0){U(r,x*8);continue}++l&&l%7===0&&K(r,x*8)}}function B(r,e){let t=e>>3;for(let o=0;o<20&&o<t;++o)U(r,o*8)}function K(r,e){n[0]=r[e+3],n[1]=r[e+4],n[2]=r[e+6],n[3]=r[e+0],n[4]=r[e+1],n[5]=r[e+2],n[6]=r[e+5],n[7]=Q[r[e+7]],r.set(n,e),n.set(u)}var Q=(()=>{let r=new Uint8Array([0,43,108,128,1,104,72,119,96,255,185,192,254,235]),e=new Uint8Array(Array.from({length:256},(o,a)=>a)),t=r.length;for(let o=0;o<t;o+=2)e[r[o+0]]=r[o+1],e[r[o+1]]=r[o+0];return e})();var V=1,W=2,ee=4,te="Master of Magic",v=46,z=Uint32Array.BYTES_PER_ELEMENT*2,d=class{constructor(e){this.fd=e;this.version=512;this.fileCount=0;this.loaded=!1;this.files=new Map;this.fileTableOffset=0;this.cache=new Map;this.cacheMaxSize=50;this.cacheOrder=[]}async getStreamReader(e,t){let o=await this.getStreamBuffer(this.fd,e,t);return new R.default(o,void 0,void 0,!0)}async load(){this.loaded||(await this.parseHeader(),await this.parseFileList(),this.loaded=!0)}async parseHeader(){let e=await this.getStreamReader(0,v);if(e.getString(15)!==te)throw new Error("Not a GRF file (invalid signature)");e.skip(15),this.fileTableOffset=e.getUint32()+v;let o=e.getUint32();if(this.fileCount=e.getUint32()-o-7,this.version=e.getUint32(),this.version!==512)throw new Error(`Unsupported version "0x${this.version.toString(16)}"`)}async parseFileList(){let e=await this.getStreamReader(this.fileTableOffset,z),t=e.getUint32(),o=e.getUint32(),a=await this.getStreamBuffer(this.fd,this.fileTableOffset+z,t),i=A.default.inflate(a),x=new TextDecoder("utf-8");for(let l=0,s=0;l<this.fileCount;++l){let b=s;for(;i[b]!==0&&b<i.length;)b++;let L=x.decode(i.subarray(s,b));s=b+1;let E={compressedSize:i[s++]|i[s++]<<8|i[s++]<<16|i[s++]<<24,lengthAligned:i[s++]|i[s++]<<8|i[s++]<<16|i[s++]<<24,realSize:i[s++]|i[s++]<<8|i[s++]<<16|i[s++]<<24,type:i[s++],offset:(i[s++]|i[s++]<<8|i[s++]<<16|i[s++]<<24)>>>0};E.type&V&&this.files.set(L,E)}}decodeEntry(e,t){return t.type&W?F(e,t.lengthAligned,t.compressedSize):t.type&ee&&B(e,t.lengthAligned),t.realSize===t.compressedSize?e:A.default.inflate(e)}addToCache(e,t){if(this.cacheOrder.length>=this.cacheMaxSize){let o=this.cacheOrder.shift();o&&this.cache.delete(o)}this.cache.set(e,t),this.cacheOrder.push(e)}getFromCache(e){let t=this.cache.get(e);if(t){let o=this.cacheOrder.indexOf(e);o>-1&&(this.cacheOrder.splice(o,1),this.cacheOrder.push(e))}return t}clearCache(){this.cache.clear(),this.cacheOrder=[]}async getFile(e){if(!this.loaded)return Promise.resolve({data:null,error:"GRF not loaded yet"});let t=e;if(!this.files.has(t))return Promise.resolve({data:null,error:`File "${t}" not found`});let o=this.getFromCache(t);if(o)return Promise.resolve({data:o,error:null});let a=this.files.get(t);if(!a)return{data:null,error:`File "${t}" not found`};let i=await this.getStreamBuffer(this.fd,a.offset+v,a.lengthAligned);try{let x=this.decodeEntry(i,a);return this.addToCache(t,x),Promise.resolve({data:x,error:null})}catch(x){return{data:null,error:x instanceof Error?x.message:String(x)}}}};var p=class extends d{async getStreamBuffer(e,t,o){return new Promise((a,i)=>{let x=new FileReader;x.onerror=i,x.onload=()=>a(new Uint8Array(x.result)),x.readAsArrayBuffer(e.slice(t,t+o))})}};var g=require("fs"),_=require("util");var w=class{constructor(){this.pools=new Map;this.maxPoolSize=10;this.poolSizes=[1024,4096,8192,16384,32768,65536,131072,262144];for(let e of this.poolSizes)this.pools.set(e,[])}getPoolSize(e){for(let t of this.poolSizes)if(e<=t)return t;return null}acquire(e){let t=this.getPoolSize(e);if(t===null)return Buffer.allocUnsafe(e);let o=this.pools.get(t);if(o){let a=o.find(i=>!i.inUse);if(a)return a.inUse=!0,a.buffer.subarray(0,e);if(o.length<this.maxPoolSize){let i=Buffer.allocUnsafe(t);return o.push({buffer:i,inUse:!0}),i.subarray(0,e)}}return Buffer.allocUnsafe(e)}release(e){let t=e.buffer.byteLength,o=this.pools.get(t);if(o){let a=o.find(i=>i.buffer===e||i.buffer.buffer===e.buffer);a&&(a.inUse=!1)}}clear(){for(let e of this.pools.values())e.length=0}stats(){let e=[];for(let[t,o]of this.pools.entries())e.push({size:t,total:o.length,inUse:o.filter(a=>a.inUse).length});return e}},m=new w;var re=(0,_.promisify)(g.read),y=class extends d{constructor(e,t){super(e),this.useBufferPool=t?.useBufferPool??!0;try{if(!(0,g.fstatSync)(e).isFile())throw new Error("GRFNode: file descriptor must point to a regular file")}catch{throw new Error("GRFNode: invalid file descriptor")}}async getStreamBuffer(e,t,o){let a=this.useBufferPool?m.acquire(o):Buffer.allocUnsafe(o),{bytesRead:i}=await re(e,a,0,o,t);if(i!==o)throw this.useBufferPool&&m.release(a),new Error("Not a GRF file (invalid signature)");return a}};0&&(module.exports={GrfBrowser,GrfNode,bufferPool});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/grf-base.ts","../src/des.ts","../src/grf-browser.ts","../src/grf-node.ts"],"sourcesContent":["export {GrfBrowser} from './grf-browser';\nexport {GrfNode} from './grf-node';\nexport type {TFileEntry} from './grf-base';\n","import {inflate} from 'pako';\nimport jDataview from 'jdataview';\nimport {decodeFull, decodeHeader} from './des';\n\nexport interface TFileEntry {\n type: number;\n offset: number;\n realSize: number;\n compressedSize: number;\n lengthAligned: number;\n}\n\nconst FILELIST_TYPE_FILE = 0x01;\nconst FILELIST_TYPE_ENCRYPT_MIXED = 0x02; // encryption mode 0 (header DES + periodic DES/shuffle)\nconst FILELIST_TYPE_ENCRYPT_HEADER = 0x04; // encryption mode 1 (header DES only)\n\nconst HEADER_SIGNATURE = 'Master of Magic';\nconst HEADER_SIZE = 46;\nconst FILE_TABLE_SIZE = Uint32Array.BYTES_PER_ELEMENT * 2;\n\nexport abstract class GrfBase<T> {\n public version = 0x200;\n public fileCount = 0;\n public loaded = false;\n public files = new Map<string, TFileEntry>();\n private fileTableOffset = 0;\n\n constructor(private fd: T) {}\n\n abstract getStreamBuffer(\n fd: T,\n offset: number,\n length: number\n ): Promise<Uint8Array>;\n\n public async getStreamReader(\n offset: number,\n length: number\n ): Promise<jDataview> {\n const buffer = await this.getStreamBuffer(this.fd, offset, length);\n\n return new jDataview(buffer, void 0, void 0, true);\n }\n\n public async load(): Promise<void> {\n if (!this.loaded) {\n await this.parseHeader();\n await this.parseFileList();\n this.loaded = true;\n }\n }\n\n private async parseHeader(): Promise<void> {\n const reader = await this.getStreamReader(0, HEADER_SIZE);\n\n const signature = reader.getString(15);\n if (signature !== HEADER_SIGNATURE) {\n throw new Error('Not a GRF file (invalid signature)');\n }\n\n reader.skip(15);\n this.fileTableOffset = reader.getUint32() + HEADER_SIZE;\n const reservedFiles = reader.getUint32();\n this.fileCount = reader.getUint32() - reservedFiles - 7;\n this.version = reader.getUint32();\n\n if (this.version !== 0x200) {\n throw new Error(`Unsupported version \"0x${this.version.toString(16)}\"`);\n }\n }\n\n private async parseFileList(): Promise<void> {\n // Read table list, stored information\n const reader = await this.getStreamReader(\n this.fileTableOffset,\n FILE_TABLE_SIZE\n );\n const compressedSize = reader.getUint32();\n const realSize = reader.getUint32();\n\n // Load the chunk and uncompress it\n const compressed = await this.getStreamBuffer(\n this.fd,\n this.fileTableOffset + FILE_TABLE_SIZE,\n compressedSize\n );\n\n const data = inflate(compressed, {\n //chunkSize: realSize\n });\n\n // Optimized version without using jDataView (faster)\n for (let i = 0, p = 0; i < this.fileCount; ++i) {\n let filename = '';\n while (data[p]) {\n filename += String.fromCharCode(data[p++]);\n }\n\n p++;\n\n // prettier-ignore\n const entry: TFileEntry = {\n compressedSize: data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24),\n lengthAligned: data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24),\n realSize: data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24),\n type: data[p++],\n offset: (data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24)) >>> 0\n };\n\n // Not a file (folder ?)\n if (entry.type & FILELIST_TYPE_FILE) {\n this.files.set(filename, entry);\n }\n }\n }\n\n private decodeEntry(data: Uint8Array, entry: TFileEntry): Uint8Array {\n // Decode the file\n if (entry.type & FILELIST_TYPE_ENCRYPT_MIXED) {\n decodeFull(data, entry.lengthAligned, entry.compressedSize);\n } else if (entry.type & FILELIST_TYPE_ENCRYPT_HEADER) {\n decodeHeader(data, entry.lengthAligned);\n }\n\n // No compression\n if (entry.realSize === entry.compressedSize) {\n return data;\n }\n\n // Uncompress\n return inflate(data, {\n //chunkSize: entry.realSize\n });\n }\n\n public async getFile(\n filename: string\n ): Promise<{data: null | Uint8Array; error: null | string}> {\n if (!this.loaded) {\n return Promise.resolve({data: null, error: 'GRF not loaded yet'});\n }\n\n const path = filename;\n\n // Not exists\n if (!this.files.has(path)) {\n return Promise.resolve({data: null, error: `File \"${path}\" not found`});\n }\n\n const entry = this.files.get(path);\n\n if (!entry) {\n return { data: null, error: `File \"${path}\" not found` };\n }\n\n const data = await this.getStreamBuffer(\n this.fd,\n entry.offset + HEADER_SIZE,\n entry.lengthAligned\n );\n\n try {\n const result = this.decodeEntry(data, entry);\n return Promise.resolve({data: result, error: null});\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n return { data: null, error: message };\n }\n }\n}\n","/**\n * Ragnarok Online DES decoder implementation\n * It's a custom one with some alterations\n */\nexport {decodeFull, decodeHeader};\n\nconst mask = new Uint8Array([0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]);\nconst tmp = new Uint8Array(8);\nconst tmp2 = new Uint8Array(8);\nconst clean = new Uint8Array(8);\n\n// prettier-ignore\nconst initialPermutationTable = new Uint8Array([\n 58, 50, 42, 34, 26, 18, 10, 2,\n 60, 52, 44, 36, 28, 20, 12, 4,\n 62, 54, 46, 38, 30, 22, 14, 6,\n 64, 56, 48, 40, 32, 24, 16, 8,\n 57, 49, 41, 33, 25, 17, 9, 1,\n 59, 51, 43, 35, 27, 19, 11, 3,\n 61, 53, 45, 37, 29, 21, 13, 5,\n 63, 55, 47, 39, 31, 23, 15, 7\n]);\n\n// prettier-ignore\nconst finalPermutationTable = new Uint8Array([\n 40, 8, 48, 16, 56, 24, 64, 32,\n 39, 7, 47, 15, 55, 23, 63, 31,\n 38, 6, 46, 14, 54, 22, 62, 30,\n 37, 5, 45, 13, 53, 21, 61, 29,\n 36, 4, 44, 12, 52, 20, 60, 28,\n 35, 3, 43, 11, 51, 19, 59, 27,\n 34, 2, 42, 10, 50, 18, 58, 26,\n 33, 1, 41, 9, 49, 17, 57, 25\n]);\n\n// prettier-ignore\nconst transpositionTable = new Uint8Array([\n 16, 7, 20, 21,\n 29, 12, 28, 17,\n 1, 15, 23, 26,\n 5, 18, 31, 10,\n 2, 8, 24, 14,\n 32, 27, 3, 9,\n 19, 13, 30, 6,\n 22, 11, 4, 25\n]);\n\n// prettier-ignore\nconst substitutionBoxTable = [\n new Uint8Array([\n 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e,\n 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85,\n 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72,\n 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9 \n ]),\n new Uint8Array([\n 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3,\n 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19,\n 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78,\n 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce\n ]),\n new Uint8Array([\n 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15,\n 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68,\n 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda,\n 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d\n ]),\n new Uint8Array([\n 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4,\n 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62,\n 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d,\n 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb\n ])\n];\n\n/**\n * Initial permutation (IP).\n */\nfunction initialPermutation(src: Uint8Array, index: number): void {\n for (let i = 0; i < 64; ++i) {\n const j = initialPermutationTable[i] - 1;\n if (src[index + ((j >> 3) & 7)] & mask[j & 7]) {\n tmp[(i >> 3) & 7] |= mask[i & 7];\n }\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Final permutation (IP^-1).\n */\nfunction finalPermutation(src: Uint8Array, index: number): void {\n for (let i = 0; i < 64; ++i) {\n const j = finalPermutationTable[i] - 1;\n if (src[index + ((j >> 3) & 7)] & mask[j & 7]) {\n tmp[(i >> 3) & 7] |= mask[i & 7];\n }\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Transposition (P-BOX).\n */\nfunction transposition(src: Uint8Array, index: number): void {\n for (let i = 0; i < 32; ++i) {\n const j = transpositionTable[i] - 1;\n if (src[index + (j >> 3)] & mask[j & 7]) {\n tmp[(i >> 3) + 4] |= mask[i & 7];\n }\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Expansion (E).\n * Expands upper four 8-bits (32b) into eight 6-bits (48b).\n */\nfunction expansion(src: Uint8Array, index: number): void {\n tmp[0] = ((src[index + 7] << 5) | (src[index + 4] >> 3)) & 0x3f; // ..0 vutsr\n tmp[1] = ((src[index + 4] << 1) | (src[index + 5] >> 7)) & 0x3f; // ..srqpo n\n tmp[2] = ((src[index + 4] << 5) | (src[index + 5] >> 3)) & 0x3f; // ..o nmlkj\n tmp[3] = ((src[index + 5] << 1) | (src[index + 6] >> 7)) & 0x3f; // ..kjihg f\n tmp[4] = ((src[index + 5] << 5) | (src[index + 6] >> 3)) & 0x3f; // ..g fedcb\n tmp[5] = ((src[index + 6] << 1) | (src[index + 7] >> 7)) & 0x3f; // ..cba98 7\n tmp[6] = ((src[index + 6] << 5) | (src[index + 7] >> 3)) & 0x3f; // ..8 76543\n tmp[7] = ((src[index + 7] << 1) | (src[index + 4] >> 7)) & 0x3f; // ..43210 v\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Substitution boxes (S-boxes).\n * NOTE: This implementation was optimized to process two nibbles in one step (twice as fast).\n */\nfunction substitutionBox(src: Uint8Array, index: number): void {\n for (let i = 0; i < 4; ++i) {\n tmp[i] =\n (substitutionBoxTable[i][src[i * 2 + 0 + index]] & 0xf0) |\n (substitutionBoxTable[i][src[i * 2 + 1 + index]] & 0x0f);\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * DES round function.\n * XORs src[0..3] with TP(SBOX(E(src[4..7]))).\n */\nfunction roundFunction(src: Uint8Array, index: number): void {\n for (let i = 0; i < 8; i++) {\n tmp2[i] = src[index + i];\n }\n\n expansion(tmp2, 0);\n substitutionBox(tmp2, 0);\n transposition(tmp2, 0);\n\n src[index + 0] ^= tmp2[4];\n src[index + 1] ^= tmp2[5];\n src[index + 2] ^= tmp2[6];\n src[index + 3] ^= tmp2[7];\n}\n\n/**\n * DEcrypt a block\n */\nfunction decryptBlock(src: Uint8Array, index: number): void {\n initialPermutation(src, index);\n roundFunction(src, index);\n finalPermutation(src, index);\n}\n\n/**\n * Decode the whole file\n */\nfunction decodeFull(\n src: Uint8Array,\n length: number,\n entryLength: number\n): void {\n // compute number of digits of the entry length\n const digits = entryLength.toString().length;\n\n // choose size of gap between two encrypted blocks\n // digits: 0 1 2 3 4 5 6 7 8 9 ...\n // cycle: 1 1 1 4 5 14 15 22 23 24 ...\n const cycle =\n digits < 3\n ? 1\n : digits < 5\n ? digits + 1\n : digits < 7\n ? digits + 9\n : digits + 15;\n\n const nblocks = length >> 3;\n\n // first 20 blocks are all des-encrypted\n for (let i = 0; i < 20 && i < nblocks; ++i) {\n decryptBlock(src, i * 8);\n }\n\n for (let i = 20, j = -1; i < nblocks; ++i) {\n // decrypt block\n if (i % cycle === 0) {\n decryptBlock(src, i * 8);\n continue;\n }\n\n // de-shuffle block\n if (++j && j % 7 === 0) {\n shuffleDec(src, i * 8);\n }\n }\n}\n\n/**\n * Decode only the header\n */\nfunction decodeHeader(src: Uint8Array, length: number): void {\n const count = length >> 3;\n\n // first 20 blocks are all des-encrypted\n for (let i = 0; i < 20 && i < count; ++i) {\n decryptBlock(src, i * 8);\n }\n\n // the rest is plaintext, done.\n}\n\n/**\n * Shuffle decode\n */\nfunction shuffleDec(src: Uint8Array, index: number) {\n tmp[0] = src[index + 3];\n tmp[1] = src[index + 4];\n tmp[2] = src[index + 6];\n tmp[3] = src[index + 0];\n tmp[4] = src[index + 1];\n tmp[5] = src[index + 2];\n tmp[6] = src[index + 5];\n tmp[7] = shuffleDecTable[src[index + 7]];\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * GRF substitution table\n */\nconst shuffleDecTable = (() => {\n // prettier-ignore\n const list = new Uint8Array([\n 0x00, 0x2b, 0x6c, 0x80, 0x01, 0x68, 0x48,\n 0x77, 0x60, 0xff, 0xb9, 0xc0, 0xfe, 0xeb\n ]);\n\n const out = new Uint8Array(Array.from({length: 256}, (_, k) => k));\n const count = list.length;\n\n for (let i = 0; i < count; i += 2) {\n out[list[i + 0]] = list[i + 1];\n out[list[i + 1]] = list[i + 0];\n }\n\n return out;\n})();\n","import jDataview from 'jdataview';\nimport {GrfBase} from './grf-base';\n\n/**\n * Using this Browser, we work from a File or Blob object.\n * We are use the FileReader API to read only some part of the file to avoid\n * loading 2 gigas into memory\n */\nexport class GrfBrowser extends GrfBase<File | Blob> {\n public async getStreamBuffer(\n buffer: File | Blob,\n offset: number,\n length: number\n ): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = reject;\n reader.onload = () =>\n resolve(new Uint8Array(reader.result as ArrayBuffer));\n reader.readAsArrayBuffer(buffer.slice(offset, offset + length));\n });\n }\n}\n","// src/grf-node.ts\nimport { readSync, fstatSync } from 'fs';\nimport { GrfBase } from './grf-base';\n\nexport class GrfNode extends GrfBase<number> {\n constructor(fd: number) {\n super(fd);\n\n // Na nossa API, apenas FDs para arquivos regulares são válidos.\n // fstatSync lança erro se o descritor não existir ou não for arquivo.\n try {\n const stat = fstatSync(fd);\n if (!stat.isFile()) {\n throw new Error('GRFNode: file descriptor must point to a regular file');\n }\n } catch {\n // Converte em mensagem clara para o usuário\n throw new Error('GRFNode: invalid file descriptor');\n }\n }\n\n public async getStreamBuffer(\n fd: number,\n offset: number,\n length: number\n ): Promise<Uint8Array> {\n const buffer = Buffer.allocUnsafe(length);\n const bytesRead = readSync(fd, buffer, 0, length, offset);\n\n if (bytesRead !== length) {\n // ERRO TYPE: GRFNode: unexpected EOF\n throw new Error('Not a GRF file (invalid signature)');\n }\n return buffer;\n }\n}\n"],"mappings":"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","names":["index_exports","__export","GrfBrowser","GrfNode","__toCommonJS","import_pako","import_jdataview","mask","tmp","tmp2","clean","initialPermutationTable","finalPermutationTable","transpositionTable","substitutionBoxTable","initialPermutation","src","index","i","j","finalPermutation","transposition","expansion","substitutionBox","roundFunction","decryptBlock","decodeFull","length","entryLength","digits","cycle","nblocks","shuffleDec","decodeHeader","count","shuffleDecTable","list","out","_","k","FILELIST_TYPE_FILE","FILELIST_TYPE_ENCRYPT_MIXED","FILELIST_TYPE_ENCRYPT_HEADER","HEADER_SIGNATURE","HEADER_SIZE","FILE_TABLE_SIZE","GrfBase","fd","offset","length","buffer","jDataview","reader","reservedFiles","compressedSize","realSize","compressed","data","i","p","filename","entry","decodeFull","decodeHeader","path","result","error","GrfBrowser","GrfBase","buffer","offset","length","resolve","reject","reader","import_fs","GrfNode","GrfBase","fd","offset","length","buffer"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/grf-base.ts","../src/des.ts","../src/grf-browser.ts","../src/grf-node.ts","../src/buffer-pool.ts"],"sourcesContent":["export {GrfBrowser} from './grf-browser';\nexport {GrfNode} from './grf-node';\nexport type {TFileEntry} from './grf-base';\nexport {bufferPool} from './buffer-pool';\n","import pako from 'pako';\nimport jDataview from 'jdataview';\nimport {decodeFull, decodeHeader} from './des';\n\nexport interface TFileEntry {\n type: number;\n offset: number;\n realSize: number;\n compressedSize: number;\n lengthAligned: number;\n}\n\nconst FILELIST_TYPE_FILE = 0x01;\nconst FILELIST_TYPE_ENCRYPT_MIXED = 0x02; // encryption mode 0 (header DES + periodic DES/shuffle)\nconst FILELIST_TYPE_ENCRYPT_HEADER = 0x04; // encryption mode 1 (header DES only)\n\nconst HEADER_SIGNATURE = 'Master of Magic';\nconst HEADER_SIZE = 46;\nconst FILE_TABLE_SIZE = Uint32Array.BYTES_PER_ELEMENT * 2;\n\nexport abstract class GrfBase<T> {\n public version = 0x200;\n public fileCount = 0;\n public loaded = false;\n public files = new Map<string, TFileEntry>();\n private fileTableOffset = 0;\n private cache = new Map<string, Uint8Array>();\n private cacheMaxSize = 50; // Max 50 files cached\n private cacheOrder: string[] = []; // LRU tracking\n\n constructor(private fd: T) {}\n\n abstract getStreamBuffer(\n fd: T,\n offset: number,\n length: number\n ): Promise<Uint8Array>;\n\n public async getStreamReader(\n offset: number,\n length: number\n ): Promise<jDataview> {\n const buffer = await this.getStreamBuffer(this.fd, offset, length);\n\n return new jDataview(buffer, void 0, void 0, true);\n }\n\n public async load(): Promise<void> {\n if (!this.loaded) {\n await this.parseHeader();\n await this.parseFileList();\n this.loaded = true;\n }\n }\n\n private async parseHeader(): Promise<void> {\n const reader = await this.getStreamReader(0, HEADER_SIZE);\n\n const signature = reader.getString(15);\n if (signature !== HEADER_SIGNATURE) {\n throw new Error('Not a GRF file (invalid signature)');\n }\n\n reader.skip(15);\n this.fileTableOffset = reader.getUint32() + HEADER_SIZE;\n const reservedFiles = reader.getUint32();\n this.fileCount = reader.getUint32() - reservedFiles - 7;\n this.version = reader.getUint32();\n\n if (this.version !== 0x200) {\n throw new Error(`Unsupported version \"0x${this.version.toString(16)}\"`);\n }\n }\n\n private async parseFileList(): Promise<void> {\n // Read table list, stored information\n const reader = await this.getStreamReader(\n this.fileTableOffset,\n FILE_TABLE_SIZE\n );\n const compressedSize = reader.getUint32();\n const realSize = reader.getUint32();\n\n // Load the chunk and uncompress it\n const compressed = await this.getStreamBuffer(\n this.fd,\n this.fileTableOffset + FILE_TABLE_SIZE,\n compressedSize\n );\n\n const data = pako.inflate(compressed);\n\n // Optimized version using TextDecoder (5-10x faster than String.fromCharCode)\n const decoder = new TextDecoder('utf-8');\n\n for (let i = 0, p = 0; i < this.fileCount; ++i) {\n // Find null terminator\n let endPos = p;\n while (data[endPos] !== 0 && endPos < data.length) {\n endPos++;\n }\n\n // Decode filename using TextDecoder (much faster)\n const filename = decoder.decode(data.subarray(p, endPos));\n\n p = endPos + 1;\n\n // prettier-ignore\n const entry: TFileEntry = {\n compressedSize: data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24),\n lengthAligned: data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24),\n realSize: data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24),\n type: data[p++],\n offset: (data[p++] | (data[p++] << 8) | (data[p++] << 16) | (data[p++] << 24)) >>> 0\n };\n\n // Not a file (folder ?)\n if (entry.type & FILELIST_TYPE_FILE) {\n this.files.set(filename, entry);\n }\n }\n }\n\n private decodeEntry(data: Uint8Array, entry: TFileEntry): Uint8Array {\n // Decode the file\n if (entry.type & FILELIST_TYPE_ENCRYPT_MIXED) {\n decodeFull(data, entry.lengthAligned, entry.compressedSize);\n } else if (entry.type & FILELIST_TYPE_ENCRYPT_HEADER) {\n decodeHeader(data, entry.lengthAligned);\n }\n\n // No compression\n if (entry.realSize === entry.compressedSize) {\n return data;\n }\n\n // Uncompress\n return pako.inflate(data);\n }\n\n private addToCache(filename: string, data: Uint8Array): void {\n // Remove oldest if cache is full\n if (this.cacheOrder.length >= this.cacheMaxSize) {\n const oldest = this.cacheOrder.shift();\n if (oldest) {\n this.cache.delete(oldest);\n }\n }\n\n // Add to cache\n this.cache.set(filename, data);\n this.cacheOrder.push(filename);\n }\n\n private getFromCache(filename: string): Uint8Array | undefined {\n const cached = this.cache.get(filename);\n if (cached) {\n // Move to end (most recently used)\n const index = this.cacheOrder.indexOf(filename);\n if (index > -1) {\n this.cacheOrder.splice(index, 1);\n this.cacheOrder.push(filename);\n }\n }\n return cached;\n }\n\n public clearCache(): void {\n this.cache.clear();\n this.cacheOrder = [];\n }\n\n public async getFile(\n filename: string\n ): Promise<{data: null | Uint8Array; error: null | string}> {\n if (!this.loaded) {\n return Promise.resolve({data: null, error: 'GRF not loaded yet'});\n }\n\n const path = filename;\n\n // Not exists\n if (!this.files.has(path)) {\n return Promise.resolve({data: null, error: `File \"${path}\" not found`});\n }\n\n // Check cache first\n const cached = this.getFromCache(path);\n if (cached) {\n return Promise.resolve({data: cached, error: null});\n }\n\n const entry = this.files.get(path);\n\n if (!entry) {\n return { data: null, error: `File \"${path}\" not found` };\n }\n\n const data = await this.getStreamBuffer(\n this.fd,\n entry.offset + HEADER_SIZE,\n entry.lengthAligned\n );\n\n try {\n const result = this.decodeEntry(data, entry);\n\n // Add to cache\n this.addToCache(path, result);\n\n return Promise.resolve({data: result, error: null});\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n return { data: null, error: message };\n }\n }\n}\n","/**\n * Ragnarok Online DES decoder implementation\n * It's a custom one with some alterations\n */\nexport {decodeFull, decodeHeader};\n\nconst mask = new Uint8Array([0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01]);\nconst tmp = new Uint8Array(8);\nconst tmp2 = new Uint8Array(8);\nconst clean = new Uint8Array(8);\n\n// prettier-ignore\nconst initialPermutationTable = new Uint8Array([\n 58, 50, 42, 34, 26, 18, 10, 2,\n 60, 52, 44, 36, 28, 20, 12, 4,\n 62, 54, 46, 38, 30, 22, 14, 6,\n 64, 56, 48, 40, 32, 24, 16, 8,\n 57, 49, 41, 33, 25, 17, 9, 1,\n 59, 51, 43, 35, 27, 19, 11, 3,\n 61, 53, 45, 37, 29, 21, 13, 5,\n 63, 55, 47, 39, 31, 23, 15, 7\n]);\n\n// prettier-ignore\nconst finalPermutationTable = new Uint8Array([\n 40, 8, 48, 16, 56, 24, 64, 32,\n 39, 7, 47, 15, 55, 23, 63, 31,\n 38, 6, 46, 14, 54, 22, 62, 30,\n 37, 5, 45, 13, 53, 21, 61, 29,\n 36, 4, 44, 12, 52, 20, 60, 28,\n 35, 3, 43, 11, 51, 19, 59, 27,\n 34, 2, 42, 10, 50, 18, 58, 26,\n 33, 1, 41, 9, 49, 17, 57, 25\n]);\n\n// prettier-ignore\nconst transpositionTable = new Uint8Array([\n 16, 7, 20, 21,\n 29, 12, 28, 17,\n 1, 15, 23, 26,\n 5, 18, 31, 10,\n 2, 8, 24, 14,\n 32, 27, 3, 9,\n 19, 13, 30, 6,\n 22, 11, 4, 25\n]);\n\n// prettier-ignore\nconst substitutionBoxTable = [\n new Uint8Array([\n 0xef, 0x03, 0x41, 0xfd, 0xd8, 0x74, 0x1e, 0x47, 0x26, 0xef, 0xfb, 0x22, 0xb3, 0xd8, 0x84, 0x1e,\n 0x39, 0xac, 0xa7, 0x60, 0x62, 0xc1, 0xcd, 0xba, 0x5c, 0x96, 0x90, 0x59, 0x05, 0x3b, 0x7a, 0x85,\n 0x40, 0xfd, 0x1e, 0xc8, 0xe7, 0x8a, 0x8b, 0x21, 0xda, 0x43, 0x64, 0x9f, 0x2d, 0x14, 0xb1, 0x72,\n 0xf5, 0x5b, 0xc8, 0xb6, 0x9c, 0x37, 0x76, 0xec, 0x39, 0xa0, 0xa3, 0x05, 0x52, 0x6e, 0x0f, 0xd9 \n ]),\n new Uint8Array([\n 0xa7, 0xdd, 0x0d, 0x78, 0x9e, 0x0b, 0xe3, 0x95, 0x60, 0x36, 0x36, 0x4f, 0xf9, 0x60, 0x5a, 0xa3,\n 0x11, 0x24, 0xd2, 0x87, 0xc8, 0x52, 0x75, 0xec, 0xbb, 0xc1, 0x4c, 0xba, 0x24, 0xfe, 0x8f, 0x19,\n 0xda, 0x13, 0x66, 0xaf, 0x49, 0xd0, 0x90, 0x06, 0x8c, 0x6a, 0xfb, 0x91, 0x37, 0x8d, 0x0d, 0x78,\n 0xbf, 0x49, 0x11, 0xf4, 0x23, 0xe5, 0xce, 0x3b, 0x55, 0xbc, 0xa2, 0x57, 0xe8, 0x22, 0x74, 0xce\n ]),\n new Uint8Array([\n 0x2c, 0xea, 0xc1, 0xbf, 0x4a, 0x24, 0x1f, 0xc2, 0x79, 0x47, 0xa2, 0x7c, 0xb6, 0xd9, 0x68, 0x15,\n 0x80, 0x56, 0x5d, 0x01, 0x33, 0xfd, 0xf4, 0xae, 0xde, 0x30, 0x07, 0x9b, 0xe5, 0x83, 0x9b, 0x68,\n 0x49, 0xb4, 0x2e, 0x83, 0x1f, 0xc2, 0xb5, 0x7c, 0xa2, 0x19, 0xd8, 0xe5, 0x7c, 0x2f, 0x83, 0xda,\n 0xf7, 0x6b, 0x90, 0xfe, 0xc4, 0x01, 0x5a, 0x97, 0x61, 0xa6, 0x3d, 0x40, 0x0b, 0x58, 0xe6, 0x3d\n ]),\n new Uint8Array([\n 0x4d, 0xd1, 0xb2, 0x0f, 0x28, 0xbd, 0xe4, 0x78, 0xf6, 0x4a, 0x0f, 0x93, 0x8b, 0x17, 0xd1, 0xa4,\n 0x3a, 0xec, 0xc9, 0x35, 0x93, 0x56, 0x7e, 0xcb, 0x55, 0x20, 0xa0, 0xfe, 0x6c, 0x89, 0x17, 0x62,\n 0x17, 0x62, 0x4b, 0xb1, 0xb4, 0xde, 0xd1, 0x87, 0xc9, 0x14, 0x3c, 0x4a, 0x7e, 0xa8, 0xe2, 0x7d,\n 0xa0, 0x9f, 0xf6, 0x5c, 0x6a, 0x09, 0x8d, 0xf0, 0x0f, 0xe3, 0x53, 0x25, 0x95, 0x36, 0x28, 0xcb\n ])\n];\n\n/**\n * Initial permutation (IP).\n */\nfunction initialPermutation(src: Uint8Array, index: number): void {\n for (let i = 0; i < 64; ++i) {\n const j = initialPermutationTable[i] - 1;\n if (src[index + ((j >> 3) & 7)] & mask[j & 7]) {\n tmp[(i >> 3) & 7] |= mask[i & 7];\n }\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Final permutation (IP^-1).\n */\nfunction finalPermutation(src: Uint8Array, index: number): void {\n for (let i = 0; i < 64; ++i) {\n const j = finalPermutationTable[i] - 1;\n if (src[index + ((j >> 3) & 7)] & mask[j & 7]) {\n tmp[(i >> 3) & 7] |= mask[i & 7];\n }\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Transposition (P-BOX).\n */\nfunction transposition(src: Uint8Array, index: number): void {\n for (let i = 0; i < 32; ++i) {\n const j = transpositionTable[i] - 1;\n if (src[index + (j >> 3)] & mask[j & 7]) {\n tmp[(i >> 3) + 4] |= mask[i & 7];\n }\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Expansion (E).\n * Expands upper four 8-bits (32b) into eight 6-bits (48b).\n */\nfunction expansion(src: Uint8Array, index: number): void {\n tmp[0] = ((src[index + 7] << 5) | (src[index + 4] >> 3)) & 0x3f; // ..0 vutsr\n tmp[1] = ((src[index + 4] << 1) | (src[index + 5] >> 7)) & 0x3f; // ..srqpo n\n tmp[2] = ((src[index + 4] << 5) | (src[index + 5] >> 3)) & 0x3f; // ..o nmlkj\n tmp[3] = ((src[index + 5] << 1) | (src[index + 6] >> 7)) & 0x3f; // ..kjihg f\n tmp[4] = ((src[index + 5] << 5) | (src[index + 6] >> 3)) & 0x3f; // ..g fedcb\n tmp[5] = ((src[index + 6] << 1) | (src[index + 7] >> 7)) & 0x3f; // ..cba98 7\n tmp[6] = ((src[index + 6] << 5) | (src[index + 7] >> 3)) & 0x3f; // ..8 76543\n tmp[7] = ((src[index + 7] << 1) | (src[index + 4] >> 7)) & 0x3f; // ..43210 v\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * Substitution boxes (S-boxes).\n * NOTE: This implementation was optimized to process two nibbles in one step (twice as fast).\n */\nfunction substitutionBox(src: Uint8Array, index: number): void {\n for (let i = 0; i < 4; ++i) {\n tmp[i] =\n (substitutionBoxTable[i][src[i * 2 + 0 + index]] & 0xf0) |\n (substitutionBoxTable[i][src[i * 2 + 1 + index]] & 0x0f);\n }\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * DES round function.\n * XORs src[0..3] with TP(SBOX(E(src[4..7]))).\n */\nfunction roundFunction(src: Uint8Array, index: number): void {\n for (let i = 0; i < 8; i++) {\n tmp2[i] = src[index + i];\n }\n\n expansion(tmp2, 0);\n substitutionBox(tmp2, 0);\n transposition(tmp2, 0);\n\n src[index + 0] ^= tmp2[4];\n src[index + 1] ^= tmp2[5];\n src[index + 2] ^= tmp2[6];\n src[index + 3] ^= tmp2[7];\n}\n\n/**\n * DEcrypt a block\n */\nfunction decryptBlock(src: Uint8Array, index: number): void {\n initialPermutation(src, index);\n roundFunction(src, index);\n finalPermutation(src, index);\n}\n\n/**\n * Decode the whole file\n */\nfunction decodeFull(\n src: Uint8Array,\n length: number,\n entryLength: number\n): void {\n // compute number of digits of the entry length\n const digits = entryLength.toString().length;\n\n // choose size of gap between two encrypted blocks\n // digits: 0 1 2 3 4 5 6 7 8 9 ...\n // cycle: 1 1 1 4 5 14 15 22 23 24 ...\n const cycle =\n digits < 3\n ? 1\n : digits < 5\n ? digits + 1\n : digits < 7\n ? digits + 9\n : digits + 15;\n\n const nblocks = length >> 3;\n\n // first 20 blocks are all des-encrypted\n for (let i = 0; i < 20 && i < nblocks; ++i) {\n decryptBlock(src, i * 8);\n }\n\n for (let i = 20, j = -1; i < nblocks; ++i) {\n // decrypt block\n if (i % cycle === 0) {\n decryptBlock(src, i * 8);\n continue;\n }\n\n // de-shuffle block\n if (++j && j % 7 === 0) {\n shuffleDec(src, i * 8);\n }\n }\n}\n\n/**\n * Decode only the header\n */\nfunction decodeHeader(src: Uint8Array, length: number): void {\n const count = length >> 3;\n\n // first 20 blocks are all des-encrypted\n for (let i = 0; i < 20 && i < count; ++i) {\n decryptBlock(src, i * 8);\n }\n\n // the rest is plaintext, done.\n}\n\n/**\n * Shuffle decode\n */\nfunction shuffleDec(src: Uint8Array, index: number) {\n tmp[0] = src[index + 3];\n tmp[1] = src[index + 4];\n tmp[2] = src[index + 6];\n tmp[3] = src[index + 0];\n tmp[4] = src[index + 1];\n tmp[5] = src[index + 2];\n tmp[6] = src[index + 5];\n tmp[7] = shuffleDecTable[src[index + 7]];\n\n src.set(tmp, index);\n tmp.set(clean);\n}\n\n/**\n * GRF substitution table\n */\nconst shuffleDecTable = (() => {\n // prettier-ignore\n const list = new Uint8Array([\n 0x00, 0x2b, 0x6c, 0x80, 0x01, 0x68, 0x48,\n 0x77, 0x60, 0xff, 0xb9, 0xc0, 0xfe, 0xeb\n ]);\n\n const out = new Uint8Array(Array.from({length: 256}, (_, k) => k));\n const count = list.length;\n\n for (let i = 0; i < count; i += 2) {\n out[list[i + 0]] = list[i + 1];\n out[list[i + 1]] = list[i + 0];\n }\n\n return out;\n})();\n","import jDataview from 'jdataview';\nimport {GrfBase} from './grf-base';\n\n/**\n * Using this Browser, we work from a File or Blob object.\n * We are use the FileReader API to read only some part of the file to avoid\n * loading 2 gigas into memory\n */\nexport class GrfBrowser extends GrfBase<File | Blob> {\n public async getStreamBuffer(\n buffer: File | Blob,\n offset: number,\n length: number\n ): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = reject;\n reader.onload = () =>\n resolve(new Uint8Array(reader.result as ArrayBuffer));\n reader.readAsArrayBuffer(buffer.slice(offset, offset + length));\n });\n }\n}\n","// src/grf-node.ts\nimport { fstatSync, read as readCallback } from 'fs';\nimport { promisify } from 'util';\nimport { GrfBase } from './grf-base';\nimport { bufferPool } from './buffer-pool';\n\nconst readAsync = promisify(readCallback);\n\nexport class GrfNode extends GrfBase<number> {\n private useBufferPool: boolean;\n\n constructor(fd: number, options?: { useBufferPool?: boolean }) {\n super(fd);\n\n this.useBufferPool = options?.useBufferPool ?? true;\n\n // Na nossa API, apenas FDs para arquivos regulares são válidos.\n // fstatSync lança erro se o descritor não existir ou não for arquivo.\n try {\n const stat = fstatSync(fd);\n if (!stat.isFile()) {\n throw new Error('GRFNode: file descriptor must point to a regular file');\n }\n } catch {\n // Converte em mensagem clara para o usuário\n throw new Error('GRFNode: invalid file descriptor');\n }\n }\n\n public async getStreamBuffer(\n fd: number,\n offset: number,\n length: number\n ): Promise<Uint8Array> {\n // Use buffer pool for better performance\n const buffer = this.useBufferPool\n ? bufferPool.acquire(length)\n : Buffer.allocUnsafe(length);\n\n const { bytesRead } = await readAsync(fd, buffer, 0, length, offset);\n\n if (bytesRead !== length) {\n // Release buffer back to pool if read failed\n if (this.useBufferPool) {\n bufferPool.release(buffer);\n }\n // ERRO TYPE: GRFNode: unexpected EOF\n throw new Error('Not a GRF file (invalid signature)');\n }\n\n return buffer;\n }\n}\n","/**\n * Simple buffer pool for reducing GC pressure\n * Pools buffers of common sizes for reuse\n */\n\ninterface PoolEntry {\n buffer: Buffer;\n inUse: boolean;\n}\n\nclass BufferPool {\n private pools = new Map<number, PoolEntry[]>();\n private maxPoolSize = 10;\n\n // Common buffer sizes to pool (in bytes)\n private readonly poolSizes = [\n 1024, // 1KB\n 4096, // 4KB\n 8192, // 8KB\n 16384, // 16KB\n 32768, // 32KB\n 65536, // 64KB\n 131072, // 128KB\n 262144, // 256KB\n ];\n\n constructor() {\n // Initialize pools for common sizes\n for (const size of this.poolSizes) {\n this.pools.set(size, []);\n }\n }\n\n /**\n * Get appropriate pool size for requested length\n */\n private getPoolSize(length: number): number | null {\n for (const size of this.poolSizes) {\n if (length <= size) {\n return size;\n }\n }\n return null; // Too large, don't pool\n }\n\n /**\n * Acquire a buffer from the pool or create new one\n */\n acquire(length: number): Buffer {\n const poolSize = this.getPoolSize(length);\n\n // Don't pool large buffers\n if (poolSize === null) {\n return Buffer.allocUnsafe(length);\n }\n\n const pool = this.pools.get(poolSize);\n\n if (pool) {\n // Try to find available buffer\n const available = pool.find(entry => !entry.inUse);\n\n if (available) {\n available.inUse = true;\n return available.buffer.subarray(0, length);\n }\n\n // Pool is full or all in use, create new if pool not maxed\n if (pool.length < this.maxPoolSize) {\n const buffer = Buffer.allocUnsafe(poolSize);\n pool.push({ buffer, inUse: true });\n return buffer.subarray(0, length);\n }\n }\n\n // Fallback: create non-pooled buffer\n return Buffer.allocUnsafe(length);\n }\n\n /**\n * Release a buffer back to the pool\n */\n release(buffer: Buffer): void {\n const actualSize = buffer.buffer.byteLength;\n const pool = this.pools.get(actualSize);\n\n if (pool) {\n const entry = pool.find(e => e.buffer === buffer || e.buffer.buffer === buffer.buffer);\n if (entry) {\n entry.inUse = false;\n }\n }\n }\n\n /**\n * Clear all pools\n */\n clear(): void {\n for (const pool of this.pools.values()) {\n pool.length = 0;\n }\n }\n\n /**\n * Get pool statistics\n */\n stats(): { size: number; total: number; inUse: number }[] {\n const stats: { size: number; total: number; inUse: number }[] = [];\n\n for (const [size, pool] of this.pools.entries()) {\n stats.push({\n size,\n total: pool.length,\n inUse: pool.filter(e => e.inUse).length\n });\n }\n\n return stats;\n }\n}\n\n// Export singleton instance\nexport const bufferPool = new BufferPool();\n"],"mappings":"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","names":["index_exports","__export","GrfBrowser","GrfNode","bufferPool","__toCommonJS","import_pako","import_jdataview","mask","tmp","tmp2","clean","initialPermutationTable","finalPermutationTable","transpositionTable","substitutionBoxTable","initialPermutation","src","index","i","j","finalPermutation","transposition","expansion","substitutionBox","roundFunction","decryptBlock","decodeFull","length","entryLength","digits","cycle","nblocks","shuffleDec","decodeHeader","count","shuffleDecTable","list","out","_","k","FILELIST_TYPE_FILE","FILELIST_TYPE_ENCRYPT_MIXED","FILELIST_TYPE_ENCRYPT_HEADER","HEADER_SIGNATURE","HEADER_SIZE","FILE_TABLE_SIZE","GrfBase","fd","offset","length","buffer","jDataview","reader","reservedFiles","compressedSize","realSize","compressed","data","pako","decoder","i","p","endPos","filename","entry","decodeFull","decodeHeader","oldest","cached","index","path","result","error","GrfBrowser","GrfBase","buffer","offset","length","resolve","reject","reader","import_fs","import_util","BufferPool","size","length","poolSize","pool","available","entry","buffer","actualSize","e","stats","bufferPool","readAsync","readCallback","GrfNode","GrfBase","fd","options","offset","length","buffer","bufferPool","bytesRead"]}
package/dist/index.d.cts CHANGED
@@ -14,6 +14,9 @@ declare abstract class GrfBase<T> {
14
14
  loaded: boolean;
15
15
  files: Map<string, TFileEntry>;
16
16
  private fileTableOffset;
17
+ private cache;
18
+ private cacheMaxSize;
19
+ private cacheOrder;
17
20
  constructor(fd: T);
18
21
  abstract getStreamBuffer(fd: T, offset: number, length: number): Promise<Uint8Array>;
19
22
  getStreamReader(offset: number, length: number): Promise<jDataview>;
@@ -21,6 +24,9 @@ declare abstract class GrfBase<T> {
21
24
  private parseHeader;
22
25
  private parseFileList;
23
26
  private decodeEntry;
27
+ private addToCache;
28
+ private getFromCache;
29
+ clearCache(): void;
24
30
  getFile(filename: string): Promise<{
25
31
  data: null | Uint8Array;
26
32
  error: null | string;
@@ -37,8 +43,47 @@ declare class GrfBrowser extends GrfBase<File | Blob> {
37
43
  }
38
44
 
39
45
  declare class GrfNode extends GrfBase<number> {
40
- constructor(fd: number);
46
+ private useBufferPool;
47
+ constructor(fd: number, options?: {
48
+ useBufferPool?: boolean;
49
+ });
41
50
  getStreamBuffer(fd: number, offset: number, length: number): Promise<Uint8Array>;
42
51
  }
43
52
 
44
- export { GrfBrowser, GrfNode, type TFileEntry };
53
+ /**
54
+ * Simple buffer pool for reducing GC pressure
55
+ * Pools buffers of common sizes for reuse
56
+ */
57
+ declare class BufferPool {
58
+ private pools;
59
+ private maxPoolSize;
60
+ private readonly poolSizes;
61
+ constructor();
62
+ /**
63
+ * Get appropriate pool size for requested length
64
+ */
65
+ private getPoolSize;
66
+ /**
67
+ * Acquire a buffer from the pool or create new one
68
+ */
69
+ acquire(length: number): Buffer;
70
+ /**
71
+ * Release a buffer back to the pool
72
+ */
73
+ release(buffer: Buffer): void;
74
+ /**
75
+ * Clear all pools
76
+ */
77
+ clear(): void;
78
+ /**
79
+ * Get pool statistics
80
+ */
81
+ stats(): {
82
+ size: number;
83
+ total: number;
84
+ inUse: number;
85
+ }[];
86
+ }
87
+ declare const bufferPool: BufferPool;
88
+
89
+ export { GrfBrowser, GrfNode, type TFileEntry, bufferPool };
package/dist/index.d.ts CHANGED
@@ -14,6 +14,9 @@ declare abstract class GrfBase<T> {
14
14
  loaded: boolean;
15
15
  files: Map<string, TFileEntry>;
16
16
  private fileTableOffset;
17
+ private cache;
18
+ private cacheMaxSize;
19
+ private cacheOrder;
17
20
  constructor(fd: T);
18
21
  abstract getStreamBuffer(fd: T, offset: number, length: number): Promise<Uint8Array>;
19
22
  getStreamReader(offset: number, length: number): Promise<jDataview>;
@@ -21,6 +24,9 @@ declare abstract class GrfBase<T> {
21
24
  private parseHeader;
22
25
  private parseFileList;
23
26
  private decodeEntry;
27
+ private addToCache;
28
+ private getFromCache;
29
+ clearCache(): void;
24
30
  getFile(filename: string): Promise<{
25
31
  data: null | Uint8Array;
26
32
  error: null | string;
@@ -37,8 +43,47 @@ declare class GrfBrowser extends GrfBase<File | Blob> {
37
43
  }
38
44
 
39
45
  declare class GrfNode extends GrfBase<number> {
40
- constructor(fd: number);
46
+ private useBufferPool;
47
+ constructor(fd: number, options?: {
48
+ useBufferPool?: boolean;
49
+ });
41
50
  getStreamBuffer(fd: number, offset: number, length: number): Promise<Uint8Array>;
42
51
  }
43
52
 
44
- export { GrfBrowser, GrfNode, type TFileEntry };
53
+ /**
54
+ * Simple buffer pool for reducing GC pressure
55
+ * Pools buffers of common sizes for reuse
56
+ */
57
+ declare class BufferPool {
58
+ private pools;
59
+ private maxPoolSize;
60
+ private readonly poolSizes;
61
+ constructor();
62
+ /**
63
+ * Get appropriate pool size for requested length
64
+ */
65
+ private getPoolSize;
66
+ /**
67
+ * Acquire a buffer from the pool or create new one
68
+ */
69
+ acquire(length: number): Buffer;
70
+ /**
71
+ * Release a buffer back to the pool
72
+ */
73
+ release(buffer: Buffer): void;
74
+ /**
75
+ * Clear all pools
76
+ */
77
+ clear(): void;
78
+ /**
79
+ * Get pool statistics
80
+ */
81
+ stats(): {
82
+ size: number;
83
+ total: number;
84
+ inUse: number;
85
+ }[];
86
+ }
87
+ declare const bufferPool: BufferPool;
88
+
89
+ export { GrfBrowser, GrfNode, type TFileEntry, bufferPool };