UNPKG

@brianpugh/tamp

Version:

Tamp compression library for JavaScript/TypeScript using WebAssembly

2 lines (1 loc) 15.4 kB
var Pe=Object.create;var M=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var _e=Object.getOwnPropertyNames;var ze=Object.getPrototypeOf,Se=Object.prototype.hasOwnProperty;var Ie=(r,e)=>{for(var t in e)M(r,t,{get:e[t],enumerable:!0})},Y=(r,e,t,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of _e(e))!Se.call(r,n)&&n!==t&&M(r,n,{get:()=>e[n],enumerable:!(s=ge(e,n))||s.enumerable});return r};var Ae=(r,e,t)=>(t=r!=null?Pe(ze(r)):{},Y(e||!r||!r.__esModule?M(t,"default",{value:r,enumerable:!0}):t,r)),Ee=r=>Y(M({},"__esModule",{value:!0}),r);var ke={};Ie(ke,{CompressionError:()=>U,DecompressionError:()=>T,ExcessBitsError:()=>$,TampCompressionStream:()=>B,TampCompressor:()=>R,TampDecompressionStream:()=>V,TampDecompressor:()=>k,TampError:()=>S,collectStream:()=>de,compress:()=>Z,compressStream:()=>le,compressText:()=>oe,computeMinPatternSize:()=>ne,createReadableStream:()=>ue,decompress:()=>X,decompressStream:()=>ce,decompressText:()=>ie,initialize:()=>re,initializeDictionary:()=>se,using:()=>ae});module.exports=Ee(ke);var ee=Ae(require("./tamp-module.js"),1),te=0,xe=-1,Ce=-2,Ue=-3,Re=-4,S=class extends Error{constructor(e,t,s={}){super(t),this.name="TampError",this.code=e,this.details=s}},$=class extends S{constructor(e="Provided data has more bits than expected literal bits",t={}){super(-2,e,t),this.name="ExcessBitsError"}},U=class extends S{constructor(e="Compression operation failed",t={}){super(-1,e,t),this.name="CompressionError"}},T=class extends S{constructor(e="Decompression operation failed",t={}){super(-1,e,t),this.name="DecompressionError"}},W=class{#e=null;#t=null;#r=null;async initialize(){return this.#t||(this.#t=this.#s()),await this.#t}async#s(){return this.#e=await(0,ee.default)(),this.#r={compressor:this.#e.ccall("tamp_compressor_sizeof","number",[],[]),decompressor:this.#e.ccall("tamp_decompressor_sizeof","number",[],[]),conf:this.#e.ccall("tamp_conf_sizeof","number",[],[])},this.#e}get module(){return this.#e}get structSizes(){return this.#r}get isInitialized(){return this.#e!==null}},F=new W;async function O(){return await F.initialize()}function C(r,e){if(r<0){let t={operation:e,code:r};switch(r){case Ce:throw new $(`${e}: Symbol has more bits than configured literal size`,t);case Ue:throw new RangeError(`${e}: Invalid configuration parameters`);case Re:throw new RangeError(`${e}: Out-of-bounds access detected in compressed data`);case xe:default:throw e.toLowerCase().includes("compress")?new U(`${e}: Operation failed`,t):e.toLowerCase().includes("decompress")?new T(`${e}: Operation failed`,t):new S(r,`${e}: Unknown error`,t)}}return r}var R=class{constructor(e={}){if(this.options={window:10,literal:8,dictionary:null,extended:!0,lazy_matching:!1,dictionary_reset:!1,append:!1,...e},this.options.window<8||this.options.window>15)throw new RangeError(`window must be between 8 and 15, got ${this.options.window}`);if(this.options.literal<5||this.options.literal>8)throw new RangeError(`literal must be between 5 and 8, got ${this.options.literal}`);this.compressorPtr=null,this.windowPtr=null,this.module=null,this._initPromise=null}async initialize(){return this._initPromise||(this._initPromise=this._doInitialize()),this._initPromise}async _doInitialize(){this.module=await O();let e=1<<this.options.window,t=this.options.dictionary?new Uint8Array(this.options.dictionary):null;if(t&&t.length!==e)throw new RangeError(`Dictionary size (${t.length}) must match window size (${e})`);let{compressor:s,conf:n}=F.structSizes,o=s+n+e;if(this.compressorPtr=this.module._malloc(o),this.compressorPtr===0)throw new RangeError(`Failed to allocate memory for compressor (${o} bytes)`);let i=this.compressorPtr+s;this.windowPtr=i+n,t?this.module.HEAPU8.set(t,this.windowPtr):this.module.ccall("tamp_initialize_dictionary",null,["number","number","number"],[this.windowPtr,e,this.options.extended?this.options.literal:8]);try{let a=this.options.window&15|(this.options.literal&15)<<4|(this.options.dictionary?1:0)<<8|(this.options.extended?1:0)<<9|(this.options.dictionary_reset?1:0)<<10|(this.options.append?1:0)<<11|(this.options.lazy_matching?1:0)<<12;this.module.setValue(i,a,"i32");let c=this.module.ccall("tamp_compressor_init","number",["number","number","number"],[this.compressorPtr,i,this.windowPtr]);C(c,"Compressor initialization")}catch(a){throw this.module._free(this.compressorPtr),this.compressorPtr=null,this.windowPtr=null,a}}async compress(e,t={}){let s=t.onPoll;if(await this.initialize(),!this.compressorPtr)throw new Error("Compressor has been destroyed");let n=1<<20,o=[],{signal:i,pollIntervalMs:a=100,pollIntervalBytes:c=65536}=t,u=performance.now(),h=u,d=0,y=0,m=()=>{if(i!=null&&i.aborted)throw new U("Compression was aborted",{aborted:!0,reason:i.reason})},l=n+n+16,b=this.module._malloc(l);if(b===0)throw new RangeError(`Failed to allocate memory (${l} bytes)`);let p=b,f=p+n,w=f+n,_=w+4,P=_+4,g=P+4;try{m();let I=e.length,H=0;for(;I>0;){m();let A=Math.min(I,n);this.module.HEAPU8.set(e.subarray(H,H+A),p);let v=p,L=A,E=0,z=0;for(;L>0&&n-z>0;){this.module.ccall("tamp_compressor_sink",null,["number","number","number","number"],[this.compressorPtr,v,L,P]);let D=this.module.getValue(P,"i32");if(v+=D,L-=D,E+=D,this.module.ccall("tamp_compressor_full","number",["number"],[this.compressorPtr])){let J=this.module.ccall("tamp_compressor_poll","number",["number","number","number","number"],[this.compressorPtr,f+z,n-z,g]),Q=this.module.getValue(g,"i32");if(z+=Q,J!==te){C(J,"Compression poll");break}if(s&&typeof s=="function"){let N=performance.now(),x=H+E,he=N-h,pe=x-d;if(he>=a||pe>=c||x===e.length){m();let q=(N-u)/1e3,K=q>0?x/q:0,fe=e.length>0?x/e.length*100:0,we=e.length-x,ye=K>0?we/K:0,be={bytesProcessed:x,totalBytes:e.length,percent:fe,bytesPerSecond:Math.round(K),estimatedTimeRemaining:ye,chunksProcessed:y,elapsedTime:q,chunkSize:Q,outputSize:z};await Promise.resolve(s(be)),h=N,d=x}}m(),y++}}if(this.module.setValue(w,z,"i32"),this.module.setValue(_,E,"i32"),z>0){let D=new Uint8Array(this.module.HEAPU8.buffer,f,z).slice();o.push(D)}if(H+=E,I-=E,E===0&&I>0)throw new U("No input consumed in compression loop",{inputRemaining:I,inputConsumed:E})}let me=o.reduce((A,v)=>A+v.length,0),j=new Uint8Array(me),G=0;for(let A of o)j.set(A,G),G+=A.length;return j}finally{this.module._free(b)}}async flush(e=!0){if(await this.initialize(),!this.compressorPtr)throw new Error("Compressor has been destroyed");let t=36,s=this.module._malloc(t);if(s===0)throw new RangeError(`Failed to allocate flush memory (${t} bytes)`);let n=s,o=s+32;try{let i=this.module.ccall("tamp_compressor_flush","number",["number","number","number","number","number"],[this.compressorPtr,n,32,o,e?1:0]);C(i,"Flush");let a=this.module.getValue(o,"i32");return new Uint8Array(this.module.HEAPU8.buffer,n,a).slice()}finally{this.module._free(s)}}async resetDictionary(){if(await this.initialize(),!this.compressorPtr)throw new Error("Compressor has been destroyed");let e=32,t=e+4,s=this.module._malloc(t);if(s===0)throw new RangeError(`Failed to allocate reset memory (${t} bytes)`);let n=s,o=s+e;try{let i=this.module.ccall("tamp_compressor_reset_dictionary","number",["number","number","number","number"],[this.compressorPtr,n,e,o]);C(i,"Reset dictionary");let a=this.module.getValue(o,"i32");return new Uint8Array(this.module.HEAPU8.buffer,n,a).slice()}finally{this.module._free(s)}}destroy(){this.compressorPtr&&(this.module._free(this.compressorPtr),this.compressorPtr=null,this.windowPtr=null)}},k=class{constructor(e={}){this.options={dictionary:null,...e},this.decompressorPtr=null,this.windowPtr=null,this.module=null,this._initPromise=null,this.initialPtr=null,this.confPtr=null,this.inputConsumedPtr=null,this.headerInputPtr=null,this.headerRead=!1,this.decompressorInitialized=!1,this.pendingInput=new Uint8Array(0)}async initialize(){return this._initPromise||(this._initPromise=this._doInitialize()),this._initPromise}async _doInitialize(){this.module=await O();let{conf:e}=F.structSizes,t=e+4+2;if(this.initialPtr=this.module._malloc(t),this.initialPtr===0)throw new RangeError(`Failed to allocate initial memory (${t} bytes)`);this.confPtr=this.initialPtr,this.inputConsumedPtr=this.initialPtr+e,this.headerInputPtr=this.inputConsumedPtr+4}async _readHeader(e){if(this.headerRead||e.length===0)return 0;let t=Math.min(e.length,2);for(let l=0;l<t;l++)this.module.setValue(this.headerInputPtr+l,e[l],"i8");let s=this.module.ccall("tamp_decompressor_read_header","number",["number","number","number","number"],[this.confPtr,this.headerInputPtr,t,this.inputConsumedPtr]);if(C(s,"Header reading"),s!==te)return this.pendingInput=e.slice(0,t),e.length;let n=this.module.getValue(this.inputConsumedPtr,"i32"),o=this.module.getValue(this.confPtr,"i32"),i=o&15,a=o>>4&15,c=o>>8&1,u=o>>9&1;if(c&&!this.options.dictionary)throw new TypeError("Compressed data requires custom dictionary but none provided");if(!c&&this.options.dictionary)throw new TypeError("Compressed data does not use custom dictionary but one was provided");let h=1<<i,d=c?new Uint8Array(this.options.dictionary):null;if(d&&d.length!==h)throw new RangeError(`Dictionary size (${d.length}) must match header window size (${h})`);let{decompressor:y}=F.structSizes,m=y+h;if(this.decompressorPtr=this.module._malloc(m),this.decompressorPtr===0)throw new RangeError(`Failed to allocate memory for decompressor (${m} bytes)`);this.windowPtr=this.decompressorPtr+y,d?this.module.HEAPU8.set(d,this.windowPtr):this.module.ccall("tamp_initialize_dictionary",null,["number","number","number"],[this.windowPtr,h,u?a:8]);try{let l=this.module.ccall("tamp_decompressor_init","number",["number","number","number","number"],[this.decompressorPtr,this.confPtr,this.windowPtr,i]);C(l,"Decompressor initialization"),this.decompressorInitialized=!0}catch(l){throw this.module._free(this.decompressorPtr),this.decompressorPtr=null,this.windowPtr=null,l}return this.headerRead=!0,n}async decompress(e,t={}){if(await this.initialize(),!this.initialPtr)throw new Error("Decompressor has been destroyed");let{signal:s}=t,n=()=>{if(s!=null&&s.aborted)throw new T("Decompression was aborted",{aborted:!0,reason:s.reason})};n();let o=new Uint8Array(this.pendingInput.length+e.length);o.set(this.pendingInput),o.set(e,this.pendingInput.length);let i=0;if(!this.headerRead){let p=await this._readHeader(o);if(i+=p,!this.headerRead||i>=o.length)return this.headerRead&&(this.pendingInput=new Uint8Array(0)),new Uint8Array(0)}let a=o.slice(i);if(a.length===0)return this.pendingInput=new Uint8Array(0),new Uint8Array(0);let c=1<<22,u=[],h=8+a.length+c,d=this.module._malloc(h);if(d===0)throw new RangeError(`Failed to allocate decompress memory (${h} bytes)`);let y=d,m=y+4,l=m+4,b=l+a.length;try{this.module.HEAPU8.set(a,l);let p=0,f=a.length;for(;f>0;){n();let w=this.module.ccall("tamp_decompressor_decompress_cb","number",["number","number","number","number","number","number","number","number","number"],[this.decompressorPtr,b,c,y,l+p,f,m,0,0]),_=this.module.getValue(y,"i32"),P=this.module.getValue(m,"i32");if(f-=P,p+=P,_>0){let g=new Uint8Array(this.module.HEAPU8.buffer,b,_).slice();u.push(g)}if(w===2){f>0?this.pendingInput=a.slice(p):this.pendingInput=new Uint8Array(0);break}else w<0&&C(w,"Decompression");if(f===0){this.pendingInput=new Uint8Array(0);break}}if(u.length===0)return new Uint8Array(0);if(u.length===1)return u[0];{let w=u.reduce((g,I)=>g+I.length,0),_=new Uint8Array(w),P=0;for(let g of u)_.set(g,P),P+=g.length;return _}}finally{this.module._free(d)}}destroy(){this.decompressorPtr&&(this.module._free(this.decompressorPtr),this.decompressorPtr=null,this.windowPtr=null),this.initialPtr&&(this.module._free(this.initialPtr),this.initialPtr=null,this.confPtr=null,this.inputConsumedPtr=null,this.headerInputPtr=null),this.headerRead=!1,this.decompressorInitialized=!1,this.pendingInput=new Uint8Array(0)}};async function Z(r,e={}){let t={},s={},{window:n,literal:o,dictionary:i,extended:a,lazy_matching:c,dictionary_reset:u,append:h,onPoll:d,signal:y,pollIntervalMs:m,pollIntervalBytes:l}=e;n!==void 0&&(t.window=n),o!==void 0&&(t.literal=o),i!==void 0&&(t.dictionary=i),a!==void 0&&(t.extended=a),c!==void 0&&(t.lazy_matching=c),u!==void 0&&(t.dictionary_reset=u),h!==void 0&&(t.append=h),s.onPoll=d,s.signal=y,m!==void 0&&(s.pollIntervalMs=m),l!==void 0&&(s.pollIntervalBytes=l);let b=new R(t);try{let p=await b.compress(r,s),f=await b.flush(t.dictionary_reset===!0),w=new Uint8Array(p.length+f.length);return w.set(p),w.set(f,p.length),w}finally{b.destroy()}}async function X(r,e={}){let t=new k(e);try{return await t.decompress(r)}finally{t.destroy()}}async function re(){await O()}async function se(r,e=8){if(!Number.isInteger(r)||r<=0||(r&r-1)!==0)throw new RangeError("Dictionary size must be a positive power of 2");if(!Number.isInteger(e)||e<5||e>8)throw new RangeError("literal must be between 5 and 8");let t=await O(),s=t._malloc(r);if(s===0)throw new RangeError(`Failed to allocate dictionary buffer (${r} bytes)`);try{return t.ccall("tamp_initialize_dictionary",null,["number","number","number"],[s,r,e]),new Uint8Array(t.HEAPU8.buffer,s,r).slice()}finally{t._free(s)}}async function ne(r,e){if(!Number.isInteger(r)||r<8||r>15)throw new RangeError("Window must be an integer between 8 and 15");if(!Number.isInteger(e)||e<5||e>8)throw new RangeError("Literal must be an integer between 5 and 8");return(await O()).ccall("tamp_compute_min_pattern_size","number",["number","number"],[r,e])}async function oe(r,e={}){let t=new TextEncoder().encode(r);return await Z(t,e)}async function ie(r,e={},t="utf-8"){let s=await X(r,e);return new TextDecoder(t).decode(s)}async function ae(r,e){try{return await e(r)}finally{r&&typeof r.destroy=="function"&&r.destroy()}}var B=class extends TransformStream{constructor(e={}){let t=null;super({start(s){t=new R(e)},async transform(s,n){try{let o=s instanceof Uint8Array?s:new Uint8Array(s),i=await t.compress(o);i.length>0&&n.enqueue(i)}catch(o){n.error(o)}},async flush(s){try{let n=await t.flush(!1);n.length>0&&s.enqueue(n)}catch(n){s.error(n)}finally{t&&(t.destroy(),t=null)}},cancel(s){t&&(t.destroy(),t=null)}})}},V=class extends TransformStream{constructor(e={}){let t=null;super({start(s){t=new k(e)},async transform(s,n){try{let o=s instanceof Uint8Array?s:new Uint8Array(s),i=await t.decompress(o);i.length>0&&n.enqueue(i)}catch(o){n.error(o)}},async flush(s){try{let n=await t.decompress(new Uint8Array(0));n.length>0&&s.enqueue(n)}catch(n){s.error(n)}finally{t&&(t.destroy(),t=null)}},cancel(s){t&&(t.destroy(),t=null)}})}};function le(r,e={}){return r.pipeThrough(new B(e))}function ce(r,e={}){return r.pipeThrough(new V(e))}function ue(r,e=8192){let t=0;return new ReadableStream({pull(s){if(t>=r.length){s.close();return}let n=r.slice(t,t+e);t+=e,s.enqueue(n)}})}async function de(r){let e=[],t=r.getReader();try{for(;;){let{done:i,value:a}=await t.read();if(i)break;e.push(a)}}finally{t.releaseLock()}let s=e.reduce((i,a)=>i+a.length,0),n=new Uint8Array(s),o=0;for(let i of e)n.set(i,o),o+=i.length;return n}0&&(module.exports={CompressionError,DecompressionError,ExcessBitsError,TampCompressionStream,TampCompressor,TampDecompressionStream,TampDecompressor,TampError,collectStream,compress,compressStream,compressText,computeMinPatternSize,createReadableStream,decompress,decompressStream,decompressText,initialize,initializeDictionary,using});