@zip.js/zip.js 2.8.25 → 2.8.28

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.
Files changed (52) hide show
  1. package/README.md +2 -2
  2. package/deno.json +1 -1
  3. package/dist/zip-core.js +1050 -569
  4. package/dist/zip-core.min.js +1 -1
  5. package/dist/zip-fs-core.js +1146 -617
  6. package/dist/zip-fs-core.min.js +1 -1
  7. package/dist/zip-fs-native.js +1207 -627
  8. package/dist/zip-fs-native.min.js +1 -1
  9. package/dist/zip-fs.js +1279 -681
  10. package/dist/zip-fs.min.js +1 -1
  11. package/dist/zip-legacy.js +1051 -570
  12. package/dist/zip-legacy.min.js +1 -1
  13. package/dist/zip-module.wasm +0 -0
  14. package/dist/zip-native.js +1053 -572
  15. package/dist/zip-native.min.js +1 -1
  16. package/dist/zip-web-worker-native.js +1 -1
  17. package/dist/zip-web-worker.js +1 -1
  18. package/dist/zip.js +1125 -626
  19. package/dist/zip.min.js +1 -1
  20. package/eslint.config.mjs +6 -1
  21. package/index-native.cjs +1207 -627
  22. package/index-native.min.js +1 -1
  23. package/index.cjs +1279 -681
  24. package/index.d.ts +2451 -2355
  25. package/index.min.js +1 -1
  26. package/lib/core/codec-pool.js +39 -1
  27. package/lib/core/codec-worker.js +120 -34
  28. package/lib/core/configuration.js +3 -0
  29. package/lib/core/constants.js +6 -0
  30. package/lib/core/io.js +55 -25
  31. package/lib/core/options.js +2 -0
  32. package/lib/core/streams/aes-crypto-stream.js +12 -12
  33. package/lib/core/streams/codec-stream.js +11 -5
  34. package/lib/core/streams/codecs/sjcl.js +1 -33
  35. package/lib/core/streams/common-crypto.js +4 -4
  36. package/lib/core/streams/zip-crypto-stream.js +25 -15
  37. package/lib/core/streams/zip-entry-stream.js +35 -1
  38. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  39. package/lib/core/streams/zlib-wasm/zlib-streams.js +73 -55
  40. package/lib/core/streams/zlib-wasm/zlib-streams.wasm +0 -0
  41. package/lib/core/util/decode-cp437.js +1 -1
  42. package/lib/core/util/decode-text.js +2 -1
  43. package/lib/core/web-worker-base.js +12 -4
  44. package/lib/core/web-worker-inline-native.js +1 -1
  45. package/lib/core/web-worker-inline-wasm.js +1 -1
  46. package/lib/core/zip-fs.js +154 -55
  47. package/lib/core/zip-reader.js +185 -67
  48. package/lib/core/zip-writer.js +613 -376
  49. package/lib/core/zlib-streams-inline.js +1 -1
  50. package/lib/zip-core-reader.js +3 -1
  51. package/lib/zip-core-writer.js +1 -0
  52. package/package.json +20 -6
package/index.cjs CHANGED
@@ -44,6 +44,7 @@ const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
44
44
  const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
45
45
  const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
46
46
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50;
47
+ const CENTRAL_FILE_HEADER_LENGTH = 46;
47
48
  const END_OF_CENTRAL_DIR_LENGTH = 22;
48
49
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20;
49
50
  const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56;
@@ -91,9 +92,11 @@ const VERSION_AES = 0x33;
91
92
  const DIRECTORY_SIGNATURE = "/";
92
93
 
93
94
  const HEADER_SIZE = 30;
95
+ const HEADER_OFFSET_VERSION = 0;
94
96
  const HEADER_OFFSET_SIGNATURE = 10;
95
97
  const HEADER_OFFSET_COMPRESSED_SIZE = 14;
96
98
  const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
99
+ const LOCAL_HEADER_COMMON_OFFSET = 4;
97
100
 
98
101
  const MAX_DATE = new Date(2107, 11, 31);
99
102
  const MIN_DATE = new Date(1980, 0, 1);
@@ -148,6 +151,7 @@ const DEFAULT_CONFIGURATION = {
148
151
  chunkSize: 64 * 1024,
149
152
  maxWorkers,
150
153
  terminateWorkerTimeout: 5000,
154
+ workerStarvationTimeout: 5000,
151
155
  useWebWorkers: true,
152
156
  useCompressionStream: true,
153
157
  CompressionStream: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
@@ -170,6 +174,7 @@ function configure(configuration) {
170
174
  chunkSize,
171
175
  maxWorkers,
172
176
  terminateWorkerTimeout,
177
+ workerStarvationTimeout,
173
178
  useCompressionStream,
174
179
  useWebWorkers,
175
180
  CompressionStream,
@@ -185,6 +190,7 @@ function configure(configuration) {
185
190
  setIfDefined("chunkSize", chunkSize);
186
191
  setIfDefined("maxWorkers", maxWorkers);
187
192
  setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
193
+ setIfDefined("workerStarvationTimeout", workerStarvationTimeout);
188
194
  setIfDefined("useCompressionStream", useCompressionStream);
189
195
  setIfDefined("useWebWorkers", useWebWorkers);
190
196
  setIfDefined("CompressionStream", CompressionStream);
@@ -199,7 +205,7 @@ function setIfDefined(propertyName, propertyValue) {
199
205
  }
200
206
  }
201
207
 
202
- function t(t){const e='(t=>{"function"==typeof define&&define.amd?define(t):t()})(function(){"use strict";const{Array:t,Object:e,Number:n,Math:s,Error:r,Uint8Array:o,Uint16Array:i,Uint32Array:c,Int32Array:a,Map:h,DataView:f,Promise:l,TextEncoder:u,crypto:w,postMessage:p,TransformStream:d,ReadableStream:y,WritableStream:m,CompressionStream:g,DecompressionStream:S}=self,b=void 0,v="undefined",k="function",z=[];for(let t=0;256>t;t++){let e=t;for(let t=0;8>t;t++)1&e?e=e>>>1^3988292384:e>>>=1;z[t]=e}class C{constructor(t){this.t=t||-1}append(t){let e=0|this.t;for(let n=0,s=0|t.length;s>n;n++)e=e>>>8^z[255&(e^t[n])];this.t=e}get(){return~this.t}}class A extends d{constructor(){let t;const e=new C;super({transform(t,n){e.append(t),n.enqueue(t)},flush(){const n=new o(4);new f(n.buffer).setUint32(0,e.get()),t.value=n}}),t=this}}const x={concat(t,e){if(0===t.length||0===e.length)return t.concat(e);const n=t[t.length-1],s=x.o(n);return 32===s?t.concat(e):x.i(e,s,0|n,t.slice(0,t.length-1))},h(t){const e=t.length;if(0===e)return 0;const n=t[e-1];return 32*(e-1)+x.o(n)},l(t,e){if(32*t.length<e)return t;const n=(t=t.slice(0,s.ceil(e/32))).length;return e&=31,n>0&&e&&(t[n-1]=x.u(e,t[n-1]&2147483648>>e-1,1)),t},u:(t,e,n)=>32===t?e:(n?0|e:e<<32-t)+1099511627776*t,o:t=>s.round(t/1099511627776)||32,i(t,e,n,s){for(void 0===s&&(s=[]);e>=32;e-=32)s.push(n),n=0;if(0===e)return s.concat(t);for(let r=0;r<t.length;r++)s.push(n|t[r]>>>e),n=t[r]<<32-e;const r=t.length?t[t.length-1]:0,o=x.o(r);return s.push(x.u(e+o&31,e+o>32?n:s.pop(),1)),s}},I={bytes:{p(t){const e=x.h(t)/8,n=new o(e);let s;for(let r=0;e>r;r++)3&r||(s=t[r/4]),n[r]=s>>>24,s<<=8;return n},m(t){const e=[];let n,s=0;for(n=0;n<t.length;n++)s=s<<8|t[n],3&~n||(e.push(s),s=0);return 3&n&&e.push(x.u(8*(3&n),s)),e}}},R=class{constructor(t){const e=this;e.blockSize=512,e.S=[1732584193,4023233417,2562383102,271733878,3285377520],e.v=[1518500249,1859775393,2400959708,3395469782],t?(e.k=t.k.slice(0),e.C=t.C.slice(0),e.A=t.A):e.reset()}reset(){const t=this;return t.k=t.S.slice(0),t.C=[],t.A=0,t}update(t){const e=this;"string"==typeof t&&(t=I.I.m(t));const n=e.C=x.concat(e.C,t),s=e.A,o=e.A=s+x.h(t);if(o>9007199254740991)throw new r("Cannot hash more than 2^53 - 1 bits");const i=new c(n);let a=0;for(let t=e.blockSize+s-(e.blockSize+s&e.blockSize-1);o>=t;t+=e.blockSize)e.R(i.subarray(16*a,16*(a+1))),a+=1;return n.splice(0,16*a),e}P(){const t=this;let e=t.C;const n=t.k;e=x.concat(e,[x.u(1,1)]);for(let t=e.length+2;15&t;t++)e.push(0);for(e.push(s.floor(t.A/4294967296)),e.push(0|t.A);e.length;)t.R(e.splice(0,16));return t.reset(),n}U(t,e,n,s){return t>19?t>39?t>59?t>79?void 0:e^n^s:e&n|e&s|n&s:e^n^s:e&n|~e&s}V(t,e){return e<<t|e>>>32-t}R(e){const n=this,r=n.k,o=t(80);for(let t=0;16>t;t++)o[t]=e[t];let i=r[0],c=r[1],a=r[2],h=r[3],f=r[4];for(let t=0;79>=t;t++){16>t||(o[t]=n.V(1,o[t-3]^o[t-8]^o[t-14]^o[t-16]));const e=n.V(5,i)+n.U(t,c,a,h)+f+o[t]+n.v[s.floor(t/20)]|0;f=h,h=a,a=n.V(30,c),c=i,i=e}r[0]=r[0]+i|0,r[1]=r[1]+c|0,r[2]=r[2]+a|0,r[3]=r[3]+h|0,r[4]=r[4]+f|0}},P={getRandomValues(t){const e=new c(t.buffer),n=t=>{let e=987654321;const n=4294967295;return()=>(e=36969*(65535&e)+(e>>16)&n,(((e<<16)+(t=18e3*(65535&t)+(t>>16)&n)&n)/4294967296+.5)*(s.random()>.5?1:-1))};for(let r,o=0;o<t.length;o+=4){const t=n(4294967296*(r||s.random()));r=987654071*t(),e[o/4]=4294967296*t()|0}return t}},U={importKey:t=>new U.M(I.bytes.m(t)),_(t,e,n,s){if(n=n||1e4,0>s||0>n)throw new r("invalid params to pbkdf2");const o=1+(s>>5)<<2;let i,c,a,h,l;const u=new ArrayBuffer(o),w=new f(u);let p=0;const d=x;for(e=I.bytes.m(e),l=1;(o||1)>p;l++){for(i=c=t.encrypt(d.concat(e,[l])),a=1;n>a;a++)for(c=t.encrypt(c),h=0;h<c.length;h++)i[h]^=c[h];for(a=0;(o||1)>p&&a<i.length;a++)w.setInt32(p,i[a]),p+=4}return u.slice(0,s/8)},M:class{constructor(t){const e=this,n=e.B=R,s=[[],[]];e.D=[new n,new n];const r=e.D[0].blockSize/32;t.length>r&&(t=(new n).update(t).P());for(let e=0;r>e;e++)s[0][e]=909522486^t[e],s[1][e]=1549556828^t[e];e.D[0].update(s[0]),e.D[1].update(s[1]),e.W=new n(e.D[0])}reset(){const t=this;t.W=new t.B(t.D[0]),t.K=!1}update(t){this.K=!0,this.W.update(t)}digest(){const t=this,e=t.W.P(),n=new t.B(t.D[1]).update(e).P();return t.reset(),n}encrypt(t){if(this.K)throw new r("encrypt on already updated hmac called!");return this.update(t),this.digest(t)}}},V=typeof w!=v&&typeof w.getRandomValues==k,M="Invalid password",_="Invalid signature",B="zipjs-abort-check-password";function D(t){return V?w.getRandomValues(t):P.getRandomValues(t)}const W=16,K={name:"PBKDF2"},E=e.assign({hash:{name:"HMAC"}},K),L=e.assign({iterations:1e3,hash:{name:"SHA-1"}},K),O=["deriveBits"],T=[8,12,16],j=[16,24,32],H=10,Z=[0,0,0,0],F=typeof w!=v,N=F&&w.subtle,q=F&&typeof N!=v,G=I.bytes,J=class{constructor(t){const e=this;e.L=[[[],[],[],[],[]],[[],[],[],[],[]]],e.L[0][0][0]||e.O();const n=e.L[0][4],s=e.L[1],o=t.length;let i,c,a,h=1;if(4!==o&&6!==o&&8!==o)throw new r("invalid aes key size");for(e.v=[c=t.slice(0),a=[]],i=o;4*o+28>i;i++){let t=c[i-1];(i%o===0||8===o&&i%o===4)&&(t=n[t>>>24]<<24^n[t>>16&255]<<16^n[t>>8&255]<<8^n[255&t],i%o===0&&(t=t<<8^t>>>24^h<<24,h=h<<1^283*(h>>7))),c[i]=c[i-o]^t}for(let t=0;i;t++,i--){const e=c[3&t?i:i-4];a[t]=4>=i||4>t?e:s[0][n[e>>>24]]^s[1][n[e>>16&255]]^s[2][n[e>>8&255]]^s[3][n[255&e]]}}encrypt(t){return this.T(t,0)}decrypt(t){return this.T(t,1)}O(){const t=this.L[0],e=this.L[1],n=t[4],s=e[4],r=[],o=[];let i,c,a,h;for(let t=0;256>t;t++)o[(r[t]=t<<1^283*(t>>7))^t]=t;for(let f=i=0;!n[f];f^=c||1,i=o[i]||1){let o=i^i<<1^i<<2^i<<3^i<<4;o=o>>8^255&o^99,n[f]=o,s[o]=f,h=r[a=r[c=r[f]]];let l=16843009*h^65537*a^257*c^16843008*f,u=257*r[o]^16843008*o;for(let n=0;4>n;n++)t[n][f]=u=u<<24^u>>>8,e[n][o]=l=l<<24^l>>>8}for(let n=0;5>n;n++)t[n]=t[n].slice(0),e[n]=e[n].slice(0)}T(t,e){if(4!==t.length)throw new r("invalid aes block size");const n=this.v[e],s=n.length/4-2,o=[0,0,0,0],i=this.L[e],c=i[0],a=i[1],h=i[2],f=i[3],l=i[4];let u,w,p,d=t[0]^n[0],y=t[e?3:1]^n[1],m=t[2]^n[2],g=t[e?1:3]^n[3],S=4;for(let t=0;s>t;t++)u=c[d>>>24]^a[y>>16&255]^h[m>>8&255]^f[255&g]^n[S],w=c[y>>>24]^a[m>>16&255]^h[g>>8&255]^f[255&d]^n[S+1],p=c[m>>>24]^a[g>>16&255]^h[d>>8&255]^f[255&y]^n[S+2],g=c[g>>>24]^a[d>>16&255]^h[y>>8&255]^f[255&m]^n[S+3],S+=4,d=u,y=w,m=p;for(let t=0;4>t;t++)o[e?3&-t:t]=l[d>>>24]<<24^l[y>>16&255]<<16^l[m>>8&255]<<8^l[255&g]^n[S++],u=d,d=y,y=m,m=g,g=u;return o}},Q=class{constructor(t,e){this.j=t,this.H=e,this.Z=e}reset(){this.Z=this.H}update(t){return this.F(this.j,t,this.Z)}N(t){if(255&~(t>>24))t+=1<<24;else{let e=t>>16&255,n=t>>8&255,s=255&t;255===e?(e=0,255===n?(n=0,255===s?s=0:++s):++n):++e,t=0,t+=e<<16,t+=n<<8,t+=s}return t}q(t){0===(t[0]=this.N(t[0]))&&(t[1]=this.N(t[1]))}F(t,e,n){let s;if(!(s=e.length))return[];const r=x.h(e);for(let r=0;s>r;r+=4){this.q(n);const s=t.encrypt(n);e[r]^=s[0],e[r+1]^=s[1],e[r+2]^=s[2],e[r+3]^=s[3]}return x.l(e,r)}},X=U.M;let Y=F&&q&&typeof N.importKey==k,$=F&&q&&typeof N.deriveBits==k;class tt extends d{constructor({password:t,rawPassword:n,signed:s,encryptionStrength:i,checkPasswordOnly:c}){super({start(){e.assign(this,{ready:new l(t=>this.G=t),password:rt(t,n),signed:s,J:i-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:i,G:a,ready:h}=n;s?(await(async(t,e,n,s)=>{const o=await st(t,e,n,it(s,0,T[e])),i=it(s,T[e]);if(o[0]!=i[0]||o[1]!=i[1])throw new r(M)})(n,i,s,it(t,0,T[i]+2)),t=it(t,T[i]+2),c?e.error(new r(B)):a()):await h;const f=new o(t.length-H-(t.length-H)%W);e.enqueue(nt(n,t,f,0,H,!0))},async flush(t){const{signed:e,X:n,Y:s,pending:i,ready:c}=this;if(s&&n){await c;const a=it(i,0,i.length-H),h=it(i,i.length-H);let f=new o;if(a.length){const t=at(G,a);s.update(t);const e=n.update(t);f=ct(G,e)}if(e){const t=it(ct(G,s.digest()),0,H);for(let e=0;H>e;e++)if(t[e]!=h[e])throw new r(_)}t.enqueue(f)}}})}}class et extends d{constructor({password:t,rawPassword:n,encryptionStrength:s}){let r;super({start(){e.assign(this,{ready:new l(t=>this.G=t),password:rt(t,n),J:s-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:r,G:i,ready:c}=n;let a=new o;s?(a=await(async(t,e,n)=>{const s=D(new o(T[e]));return ot(s,await st(t,e,n,s))})(n,r,s),i()):await c;const h=new o(a.length+t.length-t.length%W);h.set(a,0),e.enqueue(nt(n,t,h,a.length,0))},async flush(t){const{X:e,Y:n,pending:s,ready:i}=this;if(n&&e){await i;let c=new o;if(s.length){const t=e.update(at(G,s));n.update(t),c=ct(G,t)}r.signature=ct(G,n.digest()).slice(0,H),t.enqueue(ot(c,r.signature))}}}),r=this}}function nt(t,e,n,s,r,i){const{X:c,Y:a,pending:h}=t,f=e.length-r;let l;for(h.length&&(e=ot(h,e),n=((t,e)=>{if(e&&e>t.length){const n=t;(t=new o(e)).set(n,0)}return t})(n,f-f%W)),l=0;f-W>=l;l+=W){const t=at(G,it(e,l,l+W));i&&a.update(t);const r=c.update(t);i||a.update(r),n.set(ct(G,r),l+s)}return t.pending=it(e,l),n}async function st(n,s,r,i){n.password=null;const c=await(async(t,e,n,s,r)=>{if(!Y)return U.importKey(e);try{return await N.importKey("raw",e,n,!1,r)}catch{return Y=!1,U.importKey(e)}})(0,r,E,0,O),a=await(async(t,e,n)=>{if(!$)return U._(e,t.salt,L.iterations,n);try{return await N.deriveBits(t,e,n)}catch{return $=!1,U._(e,t.salt,L.iterations,n)}})(e.assign({salt:i},L),c,8*(2*j[s]+2)),h=new o(a),f=at(G,it(h,0,j[s])),l=at(G,it(h,j[s],2*j[s])),u=it(h,2*j[s]);return e.assign(n,{keys:{key:f,$:l,passwordVerification:u},X:new Q(new J(f),t.from(Z)),Y:new X(l)}),u}function rt(t,e){return e===b?(t=>{if(typeof u==v){const e=new o((t=unescape(encodeURIComponent(t))).length);for(let n=0;n<e.length;n++)e[n]=t.charCodeAt(n);return e}return(new u).encode(t)})(t):e}function ot(t,e){let n=t;return t.length+e.length&&(n=new o(t.length+e.length),n.set(t,0),n.set(e,t.length)),n}function it(t,e,n){return t.subarray(e,n)}function ct(t,e){return t.p(e)}function at(t,e){return t.m(e)}class ht extends d{constructor({password:t,passwordVerification:n,checkPasswordOnly:s}){super({start(){e.assign(this,{password:t,passwordVerification:n}),wt(this,t)},transform(t,e){const n=this;if(n.password){const e=lt(n,t.subarray(0,12));if(n.password=null,e.at(-1)!=n.passwordVerification)throw new r(M);t=t.subarray(12)}s?e.error(new r(B)):e.enqueue(lt(n,t))}})}}class ft extends d{constructor({password:t,passwordVerification:n}){super({start(){e.assign(this,{password:t,passwordVerification:n}),wt(this,t)},transform(t,e){const n=this;let s,r;if(n.password){n.password=null;const e=D(new o(12));e[11]=n.passwordVerification,s=new o(t.length+e.length),s.set(ut(n,e),0),r=12}else s=new o(t.length),r=0;s.set(ut(n,t),r),e.enqueue(s)}})}}function lt(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=dt(t)^e[s],pt(t,n[s]);return n}function ut(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=dt(t)^e[s],pt(t,e[s]);return n}function wt(t,n){const s=[305419896,591751049,878082192];e.assign(t,{keys:s,tt:new C(s[0]),et:new C(s[2])});for(let e=0;e<n.length;e++)pt(t,n.charCodeAt(e))}function pt(t,e){let[n,r,o]=t.keys;t.tt.append([e]),n=~t.tt.get(),r=mt(s.imul(mt(r+yt(n)),134775813)+1),t.et.append([r>>>24]),o=~t.et.get(),t.keys=[n,r,o]}function dt(t){const e=2|t.keys[2];return yt(s.imul(e,1^e)>>>8)}function yt(t){return 255&t}function mt(t){return 4294967295&t}class gt extends d{constructor(t,{chunkSize:e,nt:n,CompressionStream:s}){super({});const{compressed:r,encrypted:o,useCompressionStream:i,zipCrypto:c,signed:a,level:h}=t,l=this;let u,w,p=super.readable;o&&!c||!a||(u=new A,p=kt(p,u)),r&&(p=vt(p,i,{level:h,chunkSize:e},s,n,s)),o&&(c?p=kt(p,new ft(t)):(w=new et(t),p=kt(p,w))),bt(l,p,()=>{let t;o&&!c&&(t=w.signature),o&&!c||!a||(t=new f(u.value.buffer).getUint32(0)),l.signature=t})}}class St extends d{constructor(t,{chunkSize:e,st:n,DecompressionStream:s}){super({});const{zipCrypto:o,encrypted:i,signed:c,signature:a,compressed:h,useCompressionStream:l,rt:u}=t;let w,p,d=super.readable;i&&(o?d=kt(d,new ht(t)):(p=new tt(t),d=kt(d,p))),h&&(d=vt(d,l,{chunkSize:e,rt:u},s,n,s)),i&&!o||!c||(w=new A,d=kt(d,w)),bt(this,d,()=>{if((!i||o)&&c){const t=new f(w.value.buffer);if(a!=t.getUint32(0,!1))throw new r(_)}})}}function bt(t,n,s){n=kt(n,new d({flush:s})),e.defineProperty(t,"readable",{get:()=>n})}function vt(t,e,n,s,r,o){const i=e&&s?s:r||o,c=n.rt?"deflate64-raw":"deflate-raw";try{t=kt(t,new i(c,n))}catch(s){if(!e)throw s;if(r)t=kt(t,new r(c,n));else{if(!o)throw s;t=kt(t,new o(c,n))}}return t}function kt(t,e){return t.pipeThrough(e)}const zt="data",Ct="close";class At extends d{constructor(t,n){super({});const s=this,{codecType:o}=t;let i;o.startsWith("deflate")?i=gt:o.startsWith("inflate")&&(i=St),s.outputSize=0;let c=0;const a=new i(t,n),h=super.readable,f=new d({transform(t,e){t&&t.length&&(c+=t.length,e.enqueue(t))},flush(){e.assign(s,{inputSize:c})}}),l=new d({transform(e,n){if(e&&e.length&&(n.enqueue(e),s.outputSize+=e.length,t.outputSize!==b&&s.outputSize>t.outputSize))throw new r("Invalid uncompressed size")},flush(){const{signature:t}=a;e.assign(s,{signature:t,inputSize:c})}});e.defineProperty(s,"readable",{get:()=>h.pipeThrough(f).pipeThrough(a).pipeThrough(l)})}}class xt extends d{constructor(t){let e;super({transform:function n(s,r){if(e){const t=new o(e.length+s.length);t.set(e),t.set(s,e.length),s=t,e=null}s.length>t?(r.enqueue(s.slice(0,t)),n(s.slice(t),r)):e=s},flush(t){e&&e.length&&t.enqueue(e)}})}}const It=new h,Rt=new h;let Pt,Ut,Vt,Mt,_t,Bt=0;async function Dt(t){try{const{options:e,config:s}=t;if(!e.useCompressionStream)try{await self.initModule(t.config)}catch{e.useCompressionStream=!0}s.CompressionStream=self.CompressionStream,s.DecompressionStream=self.DecompressionStream;const r={highWaterMark:1},o=t.readable||new y({async pull(t){const e=new l(t=>It.set(Bt,t));Wt({type:"pull",messageId:Bt}),Bt=(Bt+1)%n.MAX_SAFE_INTEGER;const{value:s,done:r}=await e;t.enqueue(s),r&&t.close()}},r),i=t.writable||new m({async write(t){let e;const s=new l(t=>e=t);Rt.set(Bt,e),Wt({type:zt,value:t,messageId:Bt}),Bt=(Bt+1)%n.MAX_SAFE_INTEGER,await s}},r),c=new At(e,s);Pt=new AbortController;const{signal:a}=Pt;await o.pipeThrough(c).pipeThrough(new xt(s.chunkSize)).pipeTo(i,{signal:a,preventClose:!0,preventAbort:!0}),await i.getWriter().close();const{signature:h,inputSize:f,outputSize:u}=c;Wt({type:Ct,result:{signature:h,inputSize:f,outputSize:u}})}catch(t){t.outputSize=0,Kt(t)}}function Wt(t){let{value:e}=t;if(e)if(e.length)try{e=new o(e),t.value=e.buffer,p(t,[t.value])}catch{p(t)}else p(t);else p(t)}function Kt(t=new r("Unknown error")){const{message:e,stack:n,code:s,name:o,outputSize:i}=t;p({error:{message:e,stack:n,code:s,name:o,outputSize:i}})}function Et(t,e,n={}){const i="number"==typeof n.level?n.level:-1,c="number"==typeof n.ot?n.ot:65536,a="number"==typeof n.it?n.it:65536;return new d({start(){let n;if(this.ct=Vt(c),this.in=Vt(a),this.it=a,this.ht=new o(c),t?(this.ft=Ut.deflate_process,this.lt=Ut.deflate_last_consumed,this.ut=Ut.deflate_end,this.wt=Ut.deflate_new(),n="gzip"===e?Ut.deflate_init_gzip(this.wt,i):"deflate-raw"===e?Ut.deflate_init_raw(this.wt,i):Ut.deflate_init(this.wt,i)):"deflate64-raw"===e?(this.ft=Ut.inflate9_process,this.lt=Ut.inflate9_last_consumed,this.ut=Ut.inflate9_end,this.wt=Ut.inflate9_new(),n=Ut.inflate9_init_raw(this.wt)):(this.ft=Ut.inflate_process,this.lt=Ut.inflate_last_consumed,this.ut=Ut.inflate_end,this.wt=Ut.inflate_new(),n="deflate-raw"===e?Ut.inflate_init_raw(this.wt):"gzip"===e?Ut.inflate_init_gzip(this.wt):Ut.inflate_init(this.wt)),0!==n)throw new r("init failed:"+n)},transform(e,n){try{const i=e,a=new o(_t.buffer),h=this.ft,f=this.lt,l=this.ct,u=this.ht;let w=0;for(;w<i.length;){const e=s.min(i.length-w,32768);this.in&&this.it>=e||(this.in&&Mt&&Mt(this.in),this.in=Vt(e),this.it=e),a.set(i.subarray(w,w+e),this.in);const o=h(this.wt,this.in,e,l,c,0),p=16777215&o;if(p&&(u.set(a.subarray(l,l+p),0),n.enqueue(u.slice(0,p))),!t){const t=o>>24&255,e=128&t?t-256:t;if(0>e)throw new r("process error:"+e)}const d=f(this.wt);if(0===d)break;w+=d}}catch(t){this.ut&&this.wt&&this.ut(this.wt),this.in&&Mt&&Mt(this.in),this.ct&&Mt&&Mt(this.ct),n.error(t)}},flush(e){try{const n=new o(_t.buffer),s=this.ft,i=this.ct,a=this.ht;for(;;){const o=s(this.wt,0,0,i,c,4),h=16777215&o,f=o>>24&255;if(!t){const t=128&f?f-256:f;if(0>t)throw new r("process error:"+t)}if(h&&(a.set(n.subarray(i,i+h),0),e.enqueue(a.slice(0,h))),1===f||0===h)break}}catch(t){e.error(t)}finally{if(this.ut&&this.wt){const t=this.ut(this.wt);0!==t&&e.error(new r("end error:"+t))}this.in&&Mt&&Mt(this.in),this.ct&&Mt&&Mt(this.ct)}}})}addEventListener("message",({data:t})=>{const{type:e,messageId:n,value:s,done:r}=t;try{if("start"==e&&Dt(t),e==zt){const t=It.get(n);It.delete(n),t({value:new o(s),done:r})}if("ack"==e){const t=Rt.get(n);Rt.delete(n),t()}e==Ct&&Pt.abort()}catch(t){Kt(t)}});class Lt{constructor(t="deflate",e){return Et(!0,t,e)}}class Ot{constructor(t="deflate",e){return Et(!1,t,e)}}let Tt=!1;self.initModule=async t=>{try{const e=await(async(t,{baseURI:e})=>{if(!Tt){let n,s;try{try{s=new URL(t,e)}catch{}const r=await fetch(s);n=await r.arrayBuffer()}catch(e){if(!t.startsWith("data:application/wasm;base64,"))throw e;n=(t=>{const e=t.split(",")[1],n=atob(e),s=n.length,r=new o(s);for(let t=0;s>t;++t)r[t]=n.charCodeAt(t);return r.buffer})(t)}(t=>{if(Ut=t,({malloc:Vt,free:Mt,memory:_t}=Ut),"function"!=typeof Vt||"function"!=typeof Mt||!_t)throw Ut=Vt=Mt=_t=null,new r("Invalid WASM module")})((await WebAssembly.instantiate(n)).instance.exports),Tt=!0}})(t.wasmURI,t);return t.nt=Lt,t.st=Ot,e}catch{}}});\n';t({workerURI:t=>{const n="text/javascript";if(t){const t=new Blob([e],{type:n});return URL.createObjectURL(t)}return "data:"+n+","+encodeURIComponent(e)}});}
208
+ function t(t){const e='(t=>{"function"==typeof define&&define.amd?define(t):t()})(function(){"use strict";const{Array:t,Object:e,Number:n,Math:s,Error:r,Uint8Array:o,Uint16Array:i,Uint32Array:a,Int32Array:c,Map:l,DataView:f,Promise:w,TextEncoder:h,crypto:u,postMessage:p,TransformStream:d,ReadableStream:y,WritableStream:m,CompressionStream:g,DecompressionStream:S}=self,b=void 0,k="undefined",v="function",z=[];for(let t=0;256>t;t++){let e=t;for(let t=0;8>t;t++)1&e?e=e>>>1^3988292384:e>>>=1;z[t]=e}class C{constructor(t){this.t=t||-1}append(t){let e=0|this.t;for(let n=0,s=0|t.length;s>n;n++)e=e>>>8^z[255&(e^t[n])];this.t=e}get(){return~this.t}}class I extends d{constructor(){let t;const e=new C;super({transform(t,n){e.append(t),n.enqueue(t)},flush(){const n=new o(4);new f(n.buffer).setUint32(0,e.get()),t.value=n}}),t=this}}const A={concat(t,e){if(0===t.length||0===e.length)return t.concat(e);const n=t[t.length-1],s=A.o(n);return 32===s?t.concat(e):A.i(e,s,0|n,t.slice(0,t.length-1))},l(t){const e=t.length;if(0===e)return 0;const n=t[e-1];return 32*(e-1)+A.o(n)},h(t,e){if(32*t.length<e)return t;const n=(t=t.slice(0,s.ceil(e/32))).length;return e&=31,n>0&&e&&(t[n-1]=A.u(e,t[n-1]&2147483648>>e-1,1)),t},u:(t,e,n)=>32===t?e:(n?0|e:e<<32-t)+1099511627776*t,o:t=>s.round(t/1099511627776)||32,i(t,e,n,s){for(void 0===s&&(s=[]);e>=32;e-=32)s.push(n),n=0;if(0===e)return s.concat(t);for(let r=0;r<t.length;r++)s.push(n|t[r]>>>e),n=t[r]<<32-e;const r=t.length?t[t.length-1]:0,o=A.o(r);return s.push(A.u(e+o&31,e+o>32?n:s.pop(),1)),s}},P={bytes:{p(t){const e=A.l(t)/8,n=new o(e);let s;for(let r=0;e>r;r++)3&r||(s=t[r/4]),n[r]=s>>>24,s<<=8;return n},m(t){const e=[];let n,s=0;for(n=0;n<t.length;n++)s=s<<8|t[n],3&~n||(e.push(s),s=0);return 3&n&&e.push(A.u(8*(3&n),s)),e}}},x=class{constructor(t){const e=this;e.blockSize=512,e.S=[1732584193,4023233417,2562383102,271733878,3285377520],e.k=[1518500249,1859775393,2400959708,3395469782],t?(e.v=t.v.slice(0),e.C=t.C.slice(0),e.I=t.I):e.reset()}reset(){const t=this;return t.v=t.S.slice(0),t.C=[],t.I=0,t}update(t){const e=this;"string"==typeof t&&(t=P.A.m(t));const n=e.C=A.concat(e.C,t),s=e.I,o=e.I=s+A.l(t);if(o>9007199254740991)throw new r("Cannot hash more than 2^53 - 1 bits");const i=new a(n);let c=0;for(let t=e.blockSize+s-(e.blockSize+s&e.blockSize-1);o>=t;t+=e.blockSize)e.P(i.subarray(16*c,16*(c+1))),c+=1;return n.splice(0,16*c),e}R(){const t=this;let e=t.C;const n=t.v;e=A.concat(e,[A.u(1,1)]);for(let t=e.length+2;15&t;t++)e.push(0);for(e.push(s.floor(t.I/4294967296)),e.push(0|t.I);e.length;)t.P(e.splice(0,16));return t.reset(),n}U(t,e,n,s){return t>19?t>39?t>59?t>79?void 0:e^n^s:e&n|e&s|n&s:e^n^s:e&n|~e&s}W(t,e){return e<<t|e>>>32-t}P(e){const n=this,r=n.v,o=t(80);for(let t=0;16>t;t++)o[t]=e[t];let i=r[0],a=r[1],c=r[2],l=r[3],f=r[4];for(let t=0;79>=t;t++){16>t||(o[t]=n.W(1,o[t-3]^o[t-8]^o[t-14]^o[t-16]));const e=n.W(5,i)+n.U(t,a,c,l)+f+o[t]+n.k[s.floor(t/20)]|0;f=l,l=c,c=n.W(30,a),a=i,i=e}r[0]=r[0]+i|0,r[1]=r[1]+a|0,r[2]=r[2]+c|0,r[3]=r[3]+l|0,r[4]=r[4]+f|0}},R={importKey:t=>new R.D(P.bytes.m(t)),M(t,e,n,s){if(n=n||1e4,0>s||0>n)throw new r("invalid params to pbkdf2");const o=1+(s>>5)<<2;let i,a,c,l,w;const h=new ArrayBuffer(o),u=new f(h);let p=0;const d=A;for(e=P.bytes.m(e),w=1;(o||1)>p;w++){for(i=a=t.encrypt(d.concat(e,[w])),c=1;n>c;c++)for(a=t.encrypt(a),l=0;l<a.length;l++)i[l]^=a[l];for(c=0;(o||1)>p&&c<i.length;c++)u.setInt32(p,i[c]),p+=4}return h.slice(0,s/8)},D:class{constructor(t){const e=this,n=e.V=x,s=[[],[]];e._=[new n,new n];const r=e._[0].blockSize/32;t.length>r&&(t=(new n).update(t).R());for(let e=0;r>e;e++)s[0][e]=909522486^t[e],s[1][e]=1549556828^t[e];e._[0].update(s[0]),e._[1].update(s[1]),e.B=new n(e._[0])}reset(){const t=this;t.B=new t.V(t._[0]),t.T=!1}update(t){this.T=!0,this.B.update(t)}digest(){const t=this,e=t.B.R(),n=new t.V(t._[1]).update(e).R();return t.reset(),n}encrypt(t){if(this.T)throw new r("encrypt on already updated hmac called!");return this.update(t),this.digest(t)}}},U=typeof u!=k&&typeof u.getRandomValues==v,W="Invalid password",D="Invalid signature",M="zipjs-abort-check-password";function V(t){if(U)return u.getRandomValues(t);throw new r("Crypto API not supported")}const _=16,B={name:"PBKDF2"},T=e.assign({hash:{name:"HMAC"}},B),K=e.assign({iterations:1e3,hash:{name:"SHA-1"}},B),j=["deriveBits"],E=[8,12,16],L=[16,24,32],O=10,H=[0,0,0,0],Z=typeof u!=k,F=Z&&u.subtle,N=Z&&typeof F!=k,q=P.bytes,G=class{constructor(t){const e=this;e.K=[[[],[],[],[],[]],[[],[],[],[],[]]],e.K[0][0][0]||e.j();const n=e.K[0][4],s=e.K[1],o=t.length;let i,a,c,l=1;if(4!==o&&6!==o&&8!==o)throw new r("invalid aes key size");for(e.k=[a=t.slice(0),c=[]],i=o;4*o+28>i;i++){let t=a[i-1];(i%o===0||8===o&&i%o===4)&&(t=n[t>>>24]<<24^n[t>>16&255]<<16^n[t>>8&255]<<8^n[255&t],i%o===0&&(t=t<<8^t>>>24^l<<24,l=l<<1^283*(l>>7))),a[i]=a[i-o]^t}for(let t=0;i;t++,i--){const e=a[3&t?i:i-4];c[t]=4>=i||4>t?e:s[0][n[e>>>24]]^s[1][n[e>>16&255]]^s[2][n[e>>8&255]]^s[3][n[255&e]]}}encrypt(t){return this.L(t,0)}decrypt(t){return this.L(t,1)}j(){const t=this.K[0],e=this.K[1],n=t[4],s=e[4],r=[],o=[];let i,a,c,l;for(let t=0;256>t;t++)o[(r[t]=t<<1^283*(t>>7))^t]=t;for(let f=i=0;!n[f];f^=a||1,i=o[i]||1){let o=i^i<<1^i<<2^i<<3^i<<4;o=o>>8^255&o^99,n[f]=o,s[o]=f,l=r[c=r[a=r[f]]];let w=16843009*l^65537*c^257*a^16843008*f,h=257*r[o]^16843008*o;for(let n=0;4>n;n++)t[n][f]=h=h<<24^h>>>8,e[n][o]=w=w<<24^w>>>8}for(let n=0;5>n;n++)t[n]=t[n].slice(0),e[n]=e[n].slice(0)}L(t,e){if(4!==t.length)throw new r("invalid aes block size");const n=this.k[e],s=n.length/4-2,o=[0,0,0,0],i=this.K[e],a=i[0],c=i[1],l=i[2],f=i[3],w=i[4];let h,u,p,d=t[0]^n[0],y=t[e?3:1]^n[1],m=t[2]^n[2],g=t[e?1:3]^n[3],S=4;for(let t=0;s>t;t++)h=a[d>>>24]^c[y>>16&255]^l[m>>8&255]^f[255&g]^n[S],u=a[y>>>24]^c[m>>16&255]^l[g>>8&255]^f[255&d]^n[S+1],p=a[m>>>24]^c[g>>16&255]^l[d>>8&255]^f[255&y]^n[S+2],g=a[g>>>24]^c[d>>16&255]^l[y>>8&255]^f[255&m]^n[S+3],S+=4,d=h,y=u,m=p;for(let t=0;4>t;t++)o[e?3&-t:t]=w[d>>>24]<<24^w[y>>16&255]<<16^w[m>>8&255]<<8^w[255&g]^n[S++],h=d,d=y,y=m,m=g,g=h;return o}},J=class{constructor(t,e){this.O=t,this.H=e,this.Z=e}reset(){this.Z=this.H}update(t){return this.F(this.O,t,this.Z)}N(t){if(255&~(t>>24))t+=1<<24;else{let e=t>>16&255,n=t>>8&255,s=255&t;255===e?(e=0,255===n?(n=0,255===s?s=0:++s):++n):++e,t=0,t+=e<<16,t+=n<<8,t+=s}return t}q(t){0===(t[0]=this.N(t[0]))&&(t[1]=this.N(t[1]))}F(t,e,n){let s;if(!(s=e.length))return[];const r=A.l(e);for(let r=0;s>r;r+=4){this.q(n);const s=t.encrypt(n);e[r]^=s[0],e[r+1]^=s[1],e[r+2]^=s[2],e[r+3]^=s[3]}return A.h(e,r)}},Q=R.D;let X=Z&&N&&typeof F.importKey==v,Y=Z&&N&&typeof F.deriveBits==v;class $ extends d{constructor({password:t,rawPassword:n,encryptionStrength:s,checkPasswordOnly:i}){super({start(){e.assign(this,{ready:new w(t=>this.G=t),password:st(t,n),J:s-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:a,G:c,ready:l}=n;s?(await(async(t,e,n,s)=>{const o=await nt(t,e,n,ot(s,0,E[e])),i=ot(s,E[e]);if(o[0]!=i[0]||o[1]!=i[1])throw new r(W)})(n,a,s,ot(t,0,E[a]+2)),t=ot(t,E[a]+2),i?e.error(new r(M)):c()):await l;const f=new o(t.length-O-(t.length-O)%_);e.enqueue(et(n,t,f,0,O,!0))},async flush(t){const{X:e,Y:n,pending:s,ready:i}=this;if(n&&e){await i;const a=ot(s,0,s.length-O),c=ot(s,s.length-O);let l=new o;if(a.length){const t=at(q,a);n.update(t);const s=e.update(t);l=it(q,s)}const f=ot(it(q,n.digest()),0,O);let w=s.length<O?1:0;for(let t=0;O>t;t++)w|=f[t]^c[t];if(w)throw new r(D);t.enqueue(l)}}})}}class tt extends d{constructor({password:t,rawPassword:n,encryptionStrength:s}){let r;super({start(){e.assign(this,{ready:new w(t=>this.G=t),password:st(t,n),J:s-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:r,G:i,ready:a}=n;let c=new o;s?(c=await(async(t,e,n)=>{const s=V(new o(E[e]));return rt(s,await nt(t,e,n,s))})(n,r,s),i()):await a;const l=new o(c.length+t.length-t.length%_);l.set(c,0),e.enqueue(et(n,t,l,c.length,0))},async flush(t){const{X:e,Y:n,pending:s,ready:i}=this;if(n&&e){await i;let a=new o;if(s.length){const t=e.update(at(q,s));n.update(t),a=it(q,t)}r.signature=it(q,n.digest()).slice(0,O),t.enqueue(rt(a,r.signature))}}}),r=this}}function et(t,e,n,s,r,i){const{X:a,Y:c,pending:l}=t;l.length&&(e=rt(l,e));const f=e.length-r;let w;for(n=((t,e)=>{if(e&&e>t.length){const n=t;(t=new o(e)).set(n,0)}return t})(n,s+(f-f%_)),w=0;f-_>=w;w+=_){const t=at(q,ot(e,w,w+_));i&&c.update(t);const r=a.update(t);i||c.update(r),n.set(it(q,r),w+s)}return t.pending=ot(e,w),n}async function nt(n,s,r,i){n.password=null;const a=await(async(t,e,n,s,r)=>{if(!X)return R.importKey(e);try{return await F.importKey("raw",e,n,!1,r)}catch{return X=!1,R.importKey(e)}})(0,r,T,0,j),c=await(async(t,e,n)=>{if(!Y)return R.M(e,t.salt,K.iterations,n);try{return await F.deriveBits(t,e,n)}catch{return Y=!1,R.M(e,t.salt,K.iterations,n)}})(e.assign({salt:i},K),a,8*(2*L[s]+2)),l=new o(c),f=at(q,ot(l,0,L[s])),w=at(q,ot(l,L[s],2*L[s])),h=ot(l,2*L[s]);return e.assign(n,{keys:{key:f,$:w,passwordVerification:h},X:new J(new G(f),t.from(H)),Y:new Q(w)}),h}function st(t,e){return e===b?(t=>{if(typeof h==k){const e=new o((t=unescape(encodeURIComponent(t))).length);for(let n=0;n<e.length;n++)e[n]=t.charCodeAt(n);return e}return(new h).encode(t)})(t):e}function rt(t,e){let n=t;return t.length+e.length&&(n=new o(t.length+e.length),n.set(t,0),n.set(e,t.length)),n}function ot(t,e,n){return t.subarray(e,n)}function it(t,e){return t.p(e)}function at(t,e){return t.m(e)}class ct extends d{constructor({password:t,rawPassword:n,passwordVerification:s,checkPasswordOnly:o}){super({start(){e.assign(this,{password:t,rawPassword:n,passwordVerification:s}),ht(this,t,n)},transform(t,e){const n=this;if(n.password||n.rawPassword){const e=ft(n,t.subarray(0,12));if(n.password=n.rawPassword=null,0!=(e.at(-1)^n.passwordVerification))throw new r(W);t=t.subarray(12)}o?e.error(new r(M)):e.enqueue(ft(n,t))}})}}class lt extends d{constructor({password:t,rawPassword:n,passwordVerification:s}){super({start(){e.assign(this,{password:t,rawPassword:n,passwordVerification:s}),ht(this,t,n)},transform(t,e){const n=this;let s,r;if(n.password||n.rawPassword){n.password=n.rawPassword=null;const e=V(new o(12));e[11]=n.passwordVerification,s=new o(t.length+e.length),s.set(wt(n,e),0),r=12}else s=new o(t.length),r=0;s.set(wt(n,t),r),e.enqueue(s)}})}}function ft(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=pt(t)^e[s],ut(t,n[s]);return n}function wt(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=pt(t)^e[s],ut(t,e[s]);return n}function ht(t,n,s){const r=[305419896,591751049,878082192];if(e.assign(t,{keys:r,tt:new C(r[0]),et:new C(r[2])}),s)for(let e=0;e<s.length;e++)ut(t,s[e]);else for(let e=0;e<n.length;e++)ut(t,n.charCodeAt(e))}function ut(t,e){let[,n]=t.keys;t.tt.append([e]);const r=~t.tt.get();n=yt(s.imul(yt(n+dt(r)),134775813)+1),t.et.append([n>>>24]);const o=~t.et.get();t.keys=[r,n,o]}function pt(t){const e=2|t.keys[2];return dt(s.imul(e,1^e)>>>8)}function dt(t){return 255&t}function yt(t){return 4294967295&t}class mt extends d{constructor(t,{chunkSize:e,nt:n,CompressionStream:s}){super({});const{compressed:r,encrypted:o,useCompressionStream:i,zipCrypto:a,signed:c,level:l}=t,w=this;let h,u,p=super.readable;o&&!a||!c||(h=new I,p=kt(p,h)),r&&(p=bt(p,i,{level:l,chunkSize:e},s,n,s)),o&&(a?p=kt(p,new lt(t)):(u=new tt(t),p=kt(p,u))),St(w,p,()=>{let t;o&&!a&&(t=u.signature),o&&!a||!c||(t=new f(h.value.buffer).getUint32(0)),w.signature=t})}}class gt extends d{constructor(t,{chunkSize:e,st:n,DecompressionStream:s}){super({});const{zipCrypto:o,encrypted:i,signed:a,signature:c,compressed:l,useCompressionStream:w,deflate64:h}=t;let u,p,d=super.readable;i&&(o?d=kt(d,new ct(t)):(p=new $(t),d=kt(d,p))),l&&(d=bt(d,w,{chunkSize:e,deflate64:h},s,n,s),d=(t=>{const e=t.getReader();return new y({async pull(t){let n;try{n=await e.read()}catch(t){if(t&&t.message)throw t;const e=new r("Invalid compressed data");throw e.cause=t,e}const{value:s,done:o}=n;o?t.close():t.enqueue(s)},cancel:t=>e.cancel(t)})})(d)),i&&!o||!a||(u=new I,d=kt(d,u)),St(this,d,()=>{if((!i||o)&&a){const t=new f(u.value.buffer);if(c!=t.getUint32(0,!1))throw new r(D)}})}}function St(t,n,s){n=kt(n,new d({flush:s})),e.defineProperty(t,"readable",{get:()=>n})}function bt(t,e,n,s,r,o){const i=e&&s?s:r||o,a=n.deflate64?"deflate64-raw":"deflate-raw";try{t=kt(t,new i(a,n))}catch(s){if(!e)throw s;if(r)t=kt(t,new r(a,n));else{if(!o)throw s;t=kt(t,new o(a,n))}}return t}function kt(t,e){return t.pipeThrough(e)}const vt="data",zt="close";class Ct extends d{constructor(t,n){super({});const s=this,{codecType:o}=t;let i;o.startsWith("deflate")?i=mt:o.startsWith("inflate")&&(i=gt),s.outputSize=0;let a=0;const c=new i(t,n),l=super.readable,f=new d({transform(t,e){t&&t.length&&(a+=t.length,e.enqueue(t))},flush(){e.assign(s,{inputSize:a})}}),w=new d({transform(e,n){if(e&&e.length&&(n.enqueue(e),s.outputSize+=e.length,t.outputSize!==b&&s.outputSize>t.outputSize))throw new r("Invalid uncompressed size")},flush(){const{signature:t}=c;e.assign(s,{signature:t,inputSize:a})}});e.defineProperty(s,"readable",{get:()=>l.pipeThrough(f).pipeThrough(c).pipeThrough(w)})}}class It extends d{constructor(t){let e;1>t&&(t=65536),super({transform:(n,s)=>{if(e){const t=new o(e.length+n.length);t.set(e),t.set(n,e.length),n=t,e=null}let r=0;for(;n.length-r>t;)s.enqueue(n.slice(r,r+t)),r+=t;e=r?n.slice(r):n},flush(t){e&&e.length&&t.enqueue(e)}})}}let At=2;try{typeof navigator!=k&&navigator.hardwareConcurrency&&(At=navigator.hardwareConcurrency)}catch{}const Pt={rt:"./core/web-worker-wasm.js",wasmURI:"./core/streams/zlib-wasm/zlib-streams.wasm",chunkSize:65536,ot:At,it:5e3,ct:5e3,lt:!0,useCompressionStream:!0,CompressionStream:typeof g!=k&&g,DecompressionStream:typeof S!=k&&S};e.assign({},Pt);const xt=new l,Rt=new l;let Ut,Wt,Dt,Mt,Vt,_t=0;async function Bt(t){let e,r;try{const{options:o,config:i}=t;if(!o.useCompressionStream)try{await self.initModule(t.config)}catch{o.useCompressionStream=!0}i.CompressionStream=self.CompressionStream,i.DecompressionStream=self.DecompressionStream;const a={highWaterMark:1},c=t.readable||new y({async pull(t){const e=new w(t=>xt.set(_t,t));Tt({type:"pull",messageId:_t}),_t=(_t+1)%n.MAX_SAFE_INTEGER;const{value:s,done:r}=await e;t.enqueue(s),r&&t.close()}},a);r=t.writable||new m({async write(t){let e;const s=new w(t=>e=t);Rt.set(_t,e),Tt({type:vt,value:t,messageId:_t}),_t=(_t+1)%n.MAX_SAFE_INTEGER,await s}},a),e=new Ct(o,i),Ut=new AbortController;const{signal:l}=Ut;await c.pipeThrough(e).pipeThrough(new It((t=>s.max(t.chunkSize,64))(i))).pipeTo(r,{signal:l,preventClose:!0,preventAbort:!0}),await r.getWriter().close();const{signature:f,inputSize:h,outputSize:u}=e;Tt({type:zt,result:{signature:f,inputSize:h,outputSize:u}})}catch(t){if(t.outputSize=e?e.outputSize:0,r&&!r.locked)try{await r.getWriter().close()}catch{}Kt(t)}}function Tt(t){let{value:e}=t;if(e)if(e.length)try{e=new o(e),t.value=e.buffer,p(t,[t.value])}catch{p(t)}else p(t);else p(t)}function Kt(t=new r("Unknown error")){const{message:e,stack:n,code:s,name:o,outputSize:i}=t;p({error:{message:e,stack:n,code:s,name:o,outputSize:i}})}function jt(t,e,n={}){const i="number"==typeof n.level?n.level:-1,a="number"==typeof n.ft?n.ft:65536,c="number"==typeof n.wt?n.wt:65536;return new d({start(){try{let n;if(this.ht=Dt(a),this.in=Dt(c),this.wt=c,!this.ht||!this.in)throw new r("allocation failed");if(this.ut=new o(a),t?(this.dt=Wt.deflate_process,this.yt=Wt.deflate_last_consumed,this.gt=Wt.deflate_end,this.St=Wt.deflate_new(),n="gzip"===e?Wt.deflate_init_gzip(this.St,i):"deflate-raw"===e?Wt.deflate_init_raw(this.St,i):Wt.deflate_init(this.St,i)):"deflate64-raw"===e?(this.dt=Wt.inflate9_process,this.yt=Wt.inflate9_last_consumed,this.gt=Wt.inflate9_end,this.St=Wt.inflate9_new(),n=Wt.inflate9_init_raw(this.St)):(this.dt=Wt.inflate_process,this.yt=Wt.inflate_last_consumed,this.gt=Wt.inflate_end,this.St=Wt.inflate_new(),n="deflate-raw"===e?Wt.inflate_init_raw(this.St):"gzip"===e?Wt.inflate_init_gzip(this.St):Wt.inflate_init(this.St)),0!==n)throw new r("init failed:"+n)}catch(t){throw l(this),t}},transform(e,n){try{const i=e,c=new o(Vt.buffer),l=this.dt,f=this.yt,w=this.ht,h=this.ut;let u=0;for(;u<i.length;){const e=s.min(i.length-u,32768);if((!this.in||this.wt<e)&&(this.in&&Mt&&(Mt(this.in),this.in=0),this.in=Dt(e),this.wt=e,!this.in))throw new r("allocation failed");c.set(i.subarray(u,u+e),this.in);const o=l(this.St,this.in,e,w,a,0),p=16777215&o;if(p&&(h.set(c.subarray(w,w+p),0),n.enqueue(h.slice(0,p))),!t){const t=o>>24&255,e=128&t?t-256:t;if(0>e)throw new r("process error:"+e)}const d=f(this.St);if(0===d)break;u+=d}}catch(t){l(this),n.error(t)}},flush(e){try{const n=new o(Vt.buffer),s=this.dt,i=this.ht,c=this.ut;for(;;){const o=s(this.St,0,0,i,a,4),l=16777215&o,f=o>>24&255;if(!t){const t=128&f?f-256:f;if(0>t)throw new r("process error:"+t)}if(l&&(c.set(n.subarray(i,i+l),0),e.enqueue(c.slice(0,l))),1===f||0===l)break}}catch(t){e.error(t)}finally{const t=l(this);0!==t&&e.error(new r("end error:"+t))}},cancel(){l(this)}});function l(t){let e=0;return t.St&&t.gt&&(e=t.gt(t.St)),t.St=0,t.in&&Mt&&Mt(t.in),t.in=0,t.ht&&Mt&&Mt(t.ht),t.ht=0,e}}addEventListener("message",({data:t})=>{const{type:e,messageId:n,value:s,done:r}=t;try{if("start"==e&&Bt(t),e==vt){const t=xt.get(n);xt.delete(n),t({value:new o(s),done:r})}if("ack"==e){const t=Rt.get(n);Rt.delete(n),t()}e==zt&&Ut.abort()}catch(t){Kt(t)}});class Et{constructor(t="deflate",e){return jt(!0,t,e)}}class Lt{constructor(t="deflate",e){return jt(!1,t,e)}}let Ot=!1;self.initModule=async t=>{try{const e=await(async(t,{baseURI:e})=>{if(!Ot){let n,s;try{try{s=new URL(t,e)}catch{}const r=await fetch(s);n=await r.arrayBuffer()}catch(e){if(!t.startsWith("data:application/wasm;base64,"))throw e;n=(t=>{const e=t.split(",")[1],n=atob(e),s=n.length,r=new o(s);for(let t=0;s>t;++t)r[t]=n.charCodeAt(t);return r.buffer})(t)}(t=>{if(Wt=t,({malloc:Dt,free:Mt,memory:Vt}=Wt),"function"!=typeof Dt||"function"!=typeof Mt||!Vt)throw Wt=Dt=Mt=Vt=null,new r("Invalid WASM module")})((await WebAssembly.instantiate(n)).instance.exports),Ot=!0}})(t.wasmURI,t);return t.nt=Et,t.st=Lt,e}catch{}}});\n';t({workerURI:t=>{const n="text/javascript";if(t){const t=new Blob([e],{type:n});return URL.createObjectURL(t)}return "data:"+n+","+encodeURIComponent(e)}});}
203
209
 
204
210
  /*
205
211
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -948,37 +954,6 @@ cipher.aes = class {
948
954
  }
949
955
  };
950
956
 
951
- /**
952
- * Random values
953
- * @namespace
954
- */
955
- const random = {
956
- /**
957
- * Generate random words with pure js, cryptographically not as strong & safe as native implementation.
958
- * @param {TypedArray} typedArray The array to fill.
959
- * @return {TypedArray} The random values.
960
- */
961
- getRandomValues(typedArray) {
962
- const words = new Uint32Array(typedArray.buffer);
963
- const r = (m_w) => {
964
- let m_z = 0x3ade68b1;
965
- const mask = 0xffffffff;
966
- return function () {
967
- m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
968
- m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
969
- const result = ((((m_z << 0x10) + m_w) & mask) / 0x100000000) + .5;
970
- return result * (Math.random() > .5 ? 1 : -1);
971
- };
972
- };
973
- for (let i = 0, rcache; i < typedArray.length; i += 4) {
974
- const _r = r((rcache || Math.random()) * 0x100000000);
975
- rcache = _r() * 0x3ade67b7;
976
- words[i / 4] = (_r() * 0x100000000) | 0;
977
- }
978
- return typedArray;
979
- }
980
- };
981
-
982
957
  /** @fileOverview CTR mode implementation.
983
958
  *
984
959
  * Special thanks to Roy Nicholson for pointing out a bug in our
@@ -1209,12 +1184,15 @@ const GET_RANDOM_VALUES_SUPPORTED = typeof crypto != UNDEFINED_TYPE && typeof cr
1209
1184
  const ERR_INVALID_PASSWORD = "Invalid password";
1210
1185
  const ERR_INVALID_SIGNATURE = "Invalid signature";
1211
1186
  const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
1187
+ const ERR_UNSUPPORTED_CRYPTO_API = "Crypto API not supported";
1212
1188
 
1213
1189
  function getRandomValues(array) {
1214
1190
  if (GET_RANDOM_VALUES_SUPPORTED) {
1215
1191
  return crypto.getRandomValues(array);
1216
1192
  } else {
1217
- return random.getRandomValues(array);
1193
+ // all supported runtimes expose crypto.getRandomValues; failing hard beats
1194
+ // silently generating predictable encryption salts
1195
+ throw new Error(ERR_UNSUPPORTED_CRYPTO_API);
1218
1196
  }
1219
1197
  }
1220
1198
 
@@ -1273,13 +1251,12 @@ let DERIVE_BITS_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && type
1273
1251
 
1274
1252
  class AESDecryptionStream extends TransformStream {
1275
1253
 
1276
- constructor({ password, rawPassword, signed, encryptionStrength, checkPasswordOnly }) {
1254
+ constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly }) {
1277
1255
  super({
1278
1256
  start() {
1279
1257
  Object.assign(this, {
1280
1258
  ready: new Promise(resolve => this.resolveReady = resolve),
1281
1259
  password: encodePassword(password, rawPassword),
1282
- signed,
1283
1260
  strength: encryptionStrength - 1,
1284
1261
  pending: new Uint8Array()
1285
1262
  });
@@ -1308,7 +1285,6 @@ class AESDecryptionStream extends TransformStream {
1308
1285
  },
1309
1286
  async flush(controller) {
1310
1287
  const {
1311
- signed,
1312
1288
  ctr,
1313
1289
  hmac,
1314
1290
  pending,
@@ -1325,13 +1301,15 @@ class AESDecryptionStream extends TransformStream {
1325
1301
  const decryptedChunk = ctr.update(encryptedChunk);
1326
1302
  decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
1327
1303
  }
1328
- if (signed) {
1329
- const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1330
- for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1331
- if (signature[indexSignature] != originalSignature[indexSignature]) {
1332
- throw new Error(ERR_INVALID_SIGNATURE);
1333
- }
1334
- }
1304
+ const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1305
+ // branch-free comparison: accumulate the differences instead of
1306
+ // short-circuiting on the first mismatching byte
1307
+ let invalidSignature = pending.length < SIGNATURE_LENGTH ? 1 : 0;
1308
+ for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1309
+ invalidSignature |= signature[indexSignature] ^ originalSignature[indexSignature];
1310
+ }
1311
+ if (invalidSignature) {
1312
+ throw new Error(ERR_INVALID_SIGNATURE);
1335
1313
  }
1336
1314
  controller.enqueue(decryptedChunkArray);
1337
1315
  }
@@ -1403,11 +1381,11 @@ function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignat
1403
1381
  hmac,
1404
1382
  pending
1405
1383
  } = aesCrypto;
1406
- const inputLength = input.length - paddingEnd;
1407
1384
  if (pending.length) {
1408
1385
  input = concat(pending, input);
1409
- output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
1410
1386
  }
1387
+ const inputLength = input.length - paddingEnd;
1388
+ output = expand(output, paddingStart + (inputLength - (inputLength % BLOCK_LENGTH)));
1411
1389
  let offset;
1412
1390
  for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
1413
1391
  const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
@@ -1555,21 +1533,24 @@ const HEADER_LENGTH = 12;
1555
1533
 
1556
1534
  class ZipCryptoDecryptionStream extends TransformStream {
1557
1535
 
1558
- constructor({ password, passwordVerification, checkPasswordOnly }) {
1536
+ constructor({ password, rawPassword, passwordVerification, checkPasswordOnly }) {
1559
1537
  super({
1560
1538
  start() {
1561
1539
  Object.assign(this, {
1562
1540
  password,
1541
+ rawPassword,
1563
1542
  passwordVerification
1564
1543
  });
1565
- createKeys(this, password);
1544
+ createKeys(this, password, rawPassword);
1566
1545
  },
1567
1546
  transform(chunk, controller) {
1568
1547
  const zipCrypto = this;
1569
- if (zipCrypto.password) {
1548
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1570
1549
  const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
1571
- zipCrypto.password = null;
1572
- if (decryptedHeader.at(-1) != zipCrypto.passwordVerification) {
1550
+ zipCrypto.password = zipCrypto.rawPassword = null;
1551
+ // verify the password with a branch-free comparison of the verification byte, mirroring
1552
+ // the constant-time AES HMAC signature check
1553
+ if ((decryptedHeader.at(-1) ^ zipCrypto.passwordVerification) != 0) {
1573
1554
  throw new Error(ERR_INVALID_PASSWORD);
1574
1555
  }
1575
1556
  chunk = chunk.subarray(HEADER_LENGTH);
@@ -1586,21 +1567,22 @@ class ZipCryptoDecryptionStream extends TransformStream {
1586
1567
 
1587
1568
  class ZipCryptoEncryptionStream extends TransformStream {
1588
1569
 
1589
- constructor({ password, passwordVerification }) {
1570
+ constructor({ password, rawPassword, passwordVerification }) {
1590
1571
  super({
1591
1572
  start() {
1592
1573
  Object.assign(this, {
1593
1574
  password,
1575
+ rawPassword,
1594
1576
  passwordVerification
1595
1577
  });
1596
- createKeys(this, password);
1578
+ createKeys(this, password, rawPassword);
1597
1579
  },
1598
1580
  transform(chunk, controller) {
1599
1581
  const zipCrypto = this;
1600
1582
  let output;
1601
1583
  let offset;
1602
- if (zipCrypto.password) {
1603
- zipCrypto.password = null;
1584
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1585
+ zipCrypto.password = zipCrypto.rawPassword = null;
1604
1586
  const header = getRandomValues(new Uint8Array(HEADER_LENGTH));
1605
1587
  header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification;
1606
1588
  output = new Uint8Array(chunk.length + header.length);
@@ -1635,25 +1617,31 @@ function encrypt(target, input) {
1635
1617
  return output;
1636
1618
  }
1637
1619
 
1638
- function createKeys(target, password) {
1620
+ function createKeys(target, password, rawPassword) {
1639
1621
  const keys = [0x12345678, 0x23456789, 0x34567890];
1640
1622
  Object.assign(target, {
1641
1623
  keys,
1642
1624
  crcKey0: new Crc32(keys[0]),
1643
1625
  crcKey2: new Crc32(keys[2])
1644
1626
  });
1645
- for (let index = 0; index < password.length; index++) {
1646
- updateKeys(target, password.charCodeAt(index));
1627
+ if (rawPassword) {
1628
+ for (let index = 0; index < rawPassword.length; index++) {
1629
+ updateKeys(target, rawPassword[index]);
1630
+ }
1631
+ } else {
1632
+ for (let index = 0; index < password.length; index++) {
1633
+ updateKeys(target, password.charCodeAt(index));
1634
+ }
1647
1635
  }
1648
1636
  }
1649
1637
 
1650
1638
  function updateKeys(target, byte) {
1651
- let [key0, key1, key2] = target.keys;
1639
+ let [, key1] = target.keys;
1652
1640
  target.crcKey0.append([byte]);
1653
- key0 = ~target.crcKey0.get();
1641
+ const key0 = ~target.crcKey0.get();
1654
1642
  key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
1655
1643
  target.crcKey2.append([key1 >>> 24]);
1656
- key2 = ~target.crcKey2.get();
1644
+ const key2 = ~target.crcKey2.get();
1657
1645
  target.keys = [key0, key1, key2];
1658
1646
  }
1659
1647
 
@@ -1700,6 +1688,7 @@ function getInt32(number) {
1700
1688
 
1701
1689
 
1702
1690
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
1691
+ const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
1703
1692
  const FORMAT_DEFLATE_RAW = "deflate-raw";
1704
1693
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
1705
1694
 
@@ -1756,6 +1745,7 @@ class InflateStream extends TransformStream {
1756
1745
  }
1757
1746
  if (compressed) {
1758
1747
  readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
1748
+ readable = mapInflateStreamError(readable);
1759
1749
  }
1760
1750
  if ((!encrypted || zipCrypto) && signed) {
1761
1751
  crc32Stream = new Crc32Stream();
@@ -1806,6 +1796,37 @@ function pipeThrough(readable, transformStream) {
1806
1796
  return readable.pipeThrough(transformStream);
1807
1797
  }
1808
1798
 
1799
+ // DecompressionStream implementations can fail with a message-less TypeError on malformed
1800
+ // input; give these errors an identifiable message (errors raised by the other stages of
1801
+ // the pipeline, e.g. ERR_INVALID_PASSWORD, always carry a message and pass through as-is)
1802
+ function mapInflateStreamError(readable) {
1803
+ const reader = readable.getReader();
1804
+ return new ReadableStream({
1805
+ async pull(controller) {
1806
+ let result;
1807
+ try {
1808
+ result = await reader.read();
1809
+ } catch (error) {
1810
+ if (error && error.message) {
1811
+ throw error;
1812
+ }
1813
+ const mappedError = new Error(ERR_INVALID_COMPRESSED_DATA);
1814
+ mappedError.cause = error;
1815
+ throw mappedError;
1816
+ }
1817
+ const { value, done } = result;
1818
+ if (done) {
1819
+ controller.close();
1820
+ } else {
1821
+ controller.enqueue(value);
1822
+ }
1823
+ },
1824
+ cancel(reason) {
1825
+ return reader.cancel(reason);
1826
+ }
1827
+ });
1828
+ }
1829
+
1809
1830
  /*
1810
1831
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
1811
1832
 
@@ -1835,6 +1856,7 @@ function pipeThrough(readable, transformStream) {
1835
1856
  */
1836
1857
 
1837
1858
 
1859
+ const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
1838
1860
  const MESSAGE_EVENT_TYPE = "message";
1839
1861
  const MESSAGE_START = "start";
1840
1862
  const MESSAGE_PULL = "pull";
@@ -1903,6 +1925,9 @@ class ChunkStream extends TransformStream {
1903
1925
 
1904
1926
  constructor(chunkSize) {
1905
1927
  let pendingChunk;
1928
+ if (!(chunkSize >= 1)) {
1929
+ chunkSize = DEFAULT_CHUNK_SIZE$1;
1930
+ }
1906
1931
  super({
1907
1932
  transform,
1908
1933
  flush(controller) {
@@ -1920,12 +1945,12 @@ class ChunkStream extends TransformStream {
1920
1945
  chunk = newChunk;
1921
1946
  pendingChunk = null;
1922
1947
  }
1923
- if (chunk.length > chunkSize) {
1924
- controller.enqueue(chunk.slice(0, chunkSize));
1925
- transform(chunk.slice(chunkSize), controller);
1926
- } else {
1927
- pendingChunk = chunk;
1948
+ let offset = 0;
1949
+ while (chunk.length - offset > chunkSize) {
1950
+ controller.enqueue(chunk.slice(offset, offset + chunkSize));
1951
+ offset += chunkSize;
1928
1952
  }
1953
+ pendingChunk = offset ? chunk.slice(offset) : chunk;
1929
1954
  }
1930
1955
  }
1931
1956
  }
@@ -1960,8 +1985,10 @@ class ChunkStream extends TransformStream {
1960
1985
 
1961
1986
 
1962
1987
  const MODULE_WORKER_OPTIONS = { type: "module" };
1988
+ const ERROR_EVENT_TYPE = "error";
1989
+ const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
1963
1990
 
1964
- let webWorkerSupported, webWorkerURI, webWorkerOptions;
1991
+ let webWorkerSupported, webWorkerSource, webWorkerURI, webWorkerOptions;
1965
1992
  let transferStreamsSupported = true;
1966
1993
  try {
1967
1994
  transferStreamsSupported = typeof structuredClone == FUNCTION_TYPE && structuredClone(new DOMException("", "AbortError")).code !== UNDEFINED_VALUE;
@@ -1980,8 +2007,9 @@ class CodecWorker {
1980
2007
  const { signal } = streamOptions;
1981
2008
  Object.assign(workerData, {
1982
2009
  busy: true,
2010
+ generation: (workerData.generation || 0) + 1,
1983
2011
  readable: readable
1984
- .pipeThrough(new ChunkStream(config.chunkSize))
2012
+ .pipeThrough(new ChunkStream(getChunkSize(config)))
1985
2013
  .pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
1986
2014
  writable,
1987
2015
  options: Object.assign({}, options),
@@ -2004,15 +2032,17 @@ class CodecWorker {
2004
2032
  });
2005
2033
  },
2006
2034
  onTaskFinished() {
2007
- const { resolveTerminated } = workerData;
2008
- if (resolveTerminated) {
2009
- workerData.resolveTerminated = null;
2010
- workerData.terminated = true;
2011
- workerData.worker.terminate();
2012
- resolveTerminated();
2035
+ if (workerData.busy) {
2036
+ const { resolveTerminated } = workerData;
2037
+ if (resolveTerminated) {
2038
+ workerData.resolveTerminated = null;
2039
+ workerData.terminated = true;
2040
+ workerData.worker.terminate();
2041
+ resolveTerminated();
2042
+ }
2043
+ workerData.busy = false;
2044
+ onTaskFinished(workerData);
2013
2045
  }
2014
- workerData.busy = false;
2015
- onTaskFinished(workerData);
2016
2046
  }
2017
2047
  });
2018
2048
  if (webWorkerSupported === UNDEFINED_VALUE) {
@@ -2081,6 +2111,7 @@ function createWebWorkerInterface(workerData, config) {
2081
2111
  }
2082
2112
  Object.assign(workerData, {
2083
2113
  worker,
2114
+ terminated: false,
2084
2115
  interface: {
2085
2116
  run: () => runWebWorker(workerData, { chunkSize, wasmURI, baseURI })
2086
2117
  }
@@ -2135,37 +2166,85 @@ async function runWebWorker(workerData, config) {
2135
2166
  result
2136
2167
  });
2137
2168
  const { readable, options } = workerData;
2138
- const { writable, closed } = watchClosedStream(workerData.writable);
2139
- const streamsTransferred = sendMessage({
2140
- type: MESSAGE_START,
2141
- options,
2142
- config,
2143
- readable,
2144
- writable
2145
- }, workerData);
2169
+ const { writable, closed, abortPipe } = watchClosedStream(workerData.writable);
2170
+ let streamsTransferred;
2171
+ try {
2172
+ streamsTransferred = sendMessage({
2173
+ type: MESSAGE_START,
2174
+ options,
2175
+ config,
2176
+ readable,
2177
+ writable
2178
+ }, workerData);
2179
+ } catch (error) {
2180
+ abortPipe();
2181
+ try {
2182
+ await closed;
2183
+ } catch {
2184
+ // ignored
2185
+ }
2186
+ workerData.onTaskFinished();
2187
+ throw error;
2188
+ }
2146
2189
  if (!streamsTransferred) {
2147
2190
  Object.assign(workerData, {
2148
2191
  reader: readable.getReader(),
2149
2192
  writer: writable.getWriter()
2150
2193
  });
2151
2194
  }
2152
- const resultValue = await result;
2153
- if (!streamsTransferred) {
2154
- await writable.getWriter().close();
2195
+ try {
2196
+ const resultValue = await result;
2197
+ await closeWritable();
2198
+ await closed;
2199
+ return resultValue;
2200
+ } catch (error) {
2201
+ await closeWritable();
2202
+ // unblock the pipe watcher if the worker died before closing its end of the stream
2203
+ abortPipe();
2204
+ try {
2205
+ await closed;
2206
+ } catch {
2207
+ // ignored
2208
+ }
2209
+ throw error;
2210
+ }
2211
+
2212
+ async function closeWritable() {
2213
+ if (!streamsTransferred && !writable.locked) {
2214
+ try {
2215
+ await writable.getWriter().close();
2216
+ } catch {
2217
+ // ignored
2218
+ }
2219
+ }
2155
2220
  }
2156
- await closed;
2157
- return resultValue;
2158
2221
  }
2159
2222
 
2160
2223
  function watchClosedStream(writableSource) {
2224
+ const abortController = new AbortController();
2161
2225
  const { writable, readable } = new TransformStream();
2162
- const closed = readable.pipeTo(writableSource, { preventClose: true });
2163
- return { writable, closed };
2226
+ const closed = readable.pipeTo(writableSource, { preventClose: true, preventAbort: true, signal: abortController.signal });
2227
+ // the pipe can fail before `closed` is awaited (e.g. the destination write fails);
2228
+ // mark the rejection as handled so it cannot kill the process in the meantime
2229
+ closed.catch(() => { });
2230
+ return { writable, closed, abortPipe: () => abortController.abort() };
2231
+ }
2232
+
2233
+ function terminateWorker$1(workerData) {
2234
+ const { worker } = workerData;
2235
+ if (worker) {
2236
+ try {
2237
+ worker.terminate();
2238
+ } catch {
2239
+ // ignored
2240
+ }
2241
+ }
2242
+ workerData.interface = null;
2164
2243
  }
2165
2244
 
2166
2245
  function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true) {
2167
2246
  let worker, resolvedURI, resolvedOptions;
2168
- if (webWorkerURI === UNDEFINED_VALUE) {
2247
+ if (webWorkerURI === UNDEFINED_VALUE || webWorkerSource !== url) {
2169
2248
  // deno-lint-ignore valid-typeof
2170
2249
  const isFunctionURI = typeof url == FUNCTION_TYPE;
2171
2250
  if (isFunctionURI) {
@@ -2222,16 +2301,36 @@ function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true)
2222
2301
  }
2223
2302
  }
2224
2303
  }
2304
+ webWorkerSource = url;
2225
2305
  webWorkerURI = resolvedURI;
2226
2306
  webWorkerOptions = resolvedOptions;
2227
2307
  } else {
2228
2308
  worker = new Worker(webWorkerURI, webWorkerOptions);
2229
2309
  }
2230
2310
  worker.addEventListener(MESSAGE_EVENT_TYPE, event => onMessage(event, workerData));
2311
+ worker.addEventListener(ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2312
+ worker.addEventListener(MESSAGE_ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2231
2313
  return worker;
2232
2314
  }
2233
2315
 
2234
- function sendMessage(message, { worker, writer, onTaskFinished, transferStreams }) {
2316
+ function onWorkerError(event, workerData) {
2317
+ if (event.preventDefault) {
2318
+ event.preventDefault();
2319
+ }
2320
+ const { rejectResult, writer, onTaskFinished } = workerData;
2321
+ // the worker is unusable (e.g. its script failed to load); terminate it and
2322
+ // fail the current task instead of letting it hang forever
2323
+ terminateWorker$1(workerData);
2324
+ if (rejectResult) {
2325
+ rejectResult(event.error || new Error(event.message || ERROR_EVENT_TYPE));
2326
+ if (writer) {
2327
+ writer.releaseLock();
2328
+ }
2329
+ onTaskFinished();
2330
+ }
2331
+ }
2332
+
2333
+ function sendMessage(message, { worker, writer, transferStreams }) {
2235
2334
  try {
2236
2335
  const { value, readable, writable } = message;
2237
2336
  const transferables = [];
@@ -2265,14 +2364,16 @@ function sendMessage(message, { worker, writer, onTaskFinished, transferStreams
2265
2364
  if (writer) {
2266
2365
  writer.releaseLock();
2267
2366
  }
2268
- onTaskFinished();
2269
2367
  throw error;
2270
2368
  }
2271
2369
  }
2272
2370
 
2273
2371
  async function onMessage({ data }, workerData) {
2274
2372
  const { type, value, messageId, result, error } = data;
2275
- const { reader, writer, resolveResult, rejectResult, onTaskFinished } = workerData;
2373
+ const { reader, writer, resolveResult, rejectResult, onTaskFinished, generation } = workerData;
2374
+ // continuations below can settle after the worker slot has been reassigned to a new
2375
+ // task (e.g. a pending pull read failing late); they must not touch the new task
2376
+ const stale = () => workerData.generation != generation;
2276
2377
  try {
2277
2378
  if (error) {
2278
2379
  const { message, stack, code, name, outputSize } = error;
@@ -2282,23 +2383,32 @@ async function onMessage({ data }, workerData) {
2282
2383
  } else {
2283
2384
  if (type == MESSAGE_PULL) {
2284
2385
  const { value, done } = await reader.read();
2285
- sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2386
+ if (!stale()) {
2387
+ sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2388
+ }
2286
2389
  }
2287
2390
  if (type == MESSAGE_DATA) {
2288
2391
  await writer.ready;
2289
2392
  await writer.write(new Uint8Array(value));
2290
- sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2393
+ if (!stale()) {
2394
+ sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2395
+ }
2291
2396
  }
2292
2397
  if (type == MESSAGE_CLOSE) {
2293
2398
  close(null, result);
2294
2399
  }
2295
2400
  }
2296
2401
  } catch (error) {
2297
- sendMessage({ type: MESSAGE_CLOSE, messageId }, workerData);
2298
- close(error);
2402
+ if (!stale()) {
2403
+ terminateWorker$1(workerData);
2404
+ close(error);
2405
+ }
2299
2406
  }
2300
2407
 
2301
2408
  function close(error, result) {
2409
+ if (stale()) {
2410
+ return;
2411
+ }
2302
2412
  if (error) {
2303
2413
  rejectResult(error);
2304
2414
  } else {
@@ -2342,6 +2452,8 @@ async function onMessage({ data }, workerData) {
2342
2452
 
2343
2453
  let pool = [];
2344
2454
  const pendingRequests = [];
2455
+ let starvationTimeout;
2456
+ let starvationDelay;
2345
2457
 
2346
2458
  let indexWorker = 0;
2347
2459
 
@@ -2368,14 +2480,20 @@ async function runWorker(stream, workerOptions) {
2368
2480
  pool.push(workerData);
2369
2481
  return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
2370
2482
  } else {
2371
- return new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
2483
+ return new Promise(resolve => {
2484
+ pendingRequests.push({ resolve, stream, workerOptions });
2485
+ starvationDelay = config.workerStarvationTimeout;
2486
+ armStarvationTimeout();
2487
+ });
2372
2488
  }
2373
2489
  }
2374
2490
 
2375
2491
  function onTaskFinished(workerData) {
2492
+ clearStarvationTimeout();
2376
2493
  if (pendingRequests.length) {
2377
2494
  const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2378
2495
  resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
2496
+ armStarvationTimeout();
2379
2497
  } else if (workerData.worker) {
2380
2498
  clearTerminateTimeout(workerData);
2381
2499
  terminateWorker(workerData, workerOptions);
@@ -2385,6 +2503,34 @@ async function runWorker(stream, workerOptions) {
2385
2503
  }
2386
2504
  }
2387
2505
 
2506
+ function armStarvationTimeout() {
2507
+ if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
2508
+ starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
2509
+ }
2510
+ }
2511
+
2512
+ function clearStarvationTimeout() {
2513
+ if (starvationTimeout) {
2514
+ clearTimeout(starvationTimeout);
2515
+ starvationTimeout = null;
2516
+ }
2517
+ }
2518
+
2519
+ function onWorkerStarvation() {
2520
+ starvationTimeout = null;
2521
+ if (pendingRequests.length) {
2522
+ const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2523
+ const inlineWorkerOptions = Object.assign({}, workerOptions, { useWebWorkers: false, workerURI: UNDEFINED_VALUE });
2524
+ resolve(new CodecWorker({}, stream, inlineWorkerOptions, onInlineTaskFinished));
2525
+ armStarvationTimeout();
2526
+ }
2527
+ }
2528
+
2529
+ function onInlineTaskFinished() {
2530
+ clearStarvationTimeout();
2531
+ armStarvationTimeout();
2532
+ }
2533
+
2388
2534
  function terminateWorker(workerData, workerOptions) {
2389
2535
  const { config } = workerOptions;
2390
2536
  const { terminateWorkerTimeout } = config;
@@ -2455,6 +2601,7 @@ const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
2455
2601
 
2456
2602
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
2457
2603
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
2604
+ const HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
2458
2605
  const HTTP_HEADER_CONTENT_RANGE = "Content-Range";
2459
2606
  const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges";
2460
2607
  const HTTP_HEADER_RANGE = "Range";
@@ -2579,7 +2726,7 @@ class Data64URIWriter extends Writer {
2579
2726
 
2580
2727
  writeUint8Array(array) {
2581
2728
  const writer = this;
2582
- let indexArray = 0;
2729
+ let indexArray;
2583
2730
  let dataString = writer.pending;
2584
2731
  const delta = writer.pending.length;
2585
2732
  writer.pending = "";
@@ -2589,12 +2736,10 @@ class Data64URIWriter extends Writer {
2589
2736
  for (; indexArray < array.length; indexArray++) {
2590
2737
  writer.pending += String.fromCharCode(array[indexArray]);
2591
2738
  }
2592
- if (dataString.length) {
2593
- if (dataString.length > 2) {
2594
- writer.data += btoa(dataString);
2595
- } else {
2596
- writer.pending += dataString;
2597
- }
2739
+ if (dataString.length > 2) {
2740
+ writer.data += btoa(dataString);
2741
+ } else {
2742
+ writer.pending = dataString + writer.pending;
2598
2743
  }
2599
2744
  }
2600
2745
 
@@ -2641,6 +2786,9 @@ class BlobWriter extends Stream {
2641
2786
  }
2642
2787
  });
2643
2788
  writer.blob = new Response(transformStream.readable, { headers }).blob();
2789
+ // mark early rejections (e.g. aborted pipe) as handled; awaiting getData() still
2790
+ // surfaces them
2791
+ writer.blob.catch(() => { });
2644
2792
  }
2645
2793
 
2646
2794
  getData() {
@@ -2725,7 +2873,8 @@ function createHttpReader(httpReader, url, options) {
2725
2873
  preventHeadRequest,
2726
2874
  useRangeHeader,
2727
2875
  forceRangeRequests,
2728
- combineSizeEocd
2876
+ combineSizeEocd,
2877
+ fetch
2729
2878
  } = options;
2730
2879
  options = Object.assign({}, options);
2731
2880
  delete options.preventHeadRequest;
@@ -2733,13 +2882,15 @@ function createHttpReader(httpReader, url, options) {
2733
2882
  delete options.forceRangeRequests;
2734
2883
  delete options.combineSizeEocd;
2735
2884
  delete options.useXHR;
2885
+ delete options.fetch;
2736
2886
  Object.assign(httpReader, {
2737
2887
  url,
2738
2888
  options,
2739
2889
  preventHeadRequest,
2740
2890
  useRangeHeader,
2741
2891
  forceRangeRequests,
2742
- combineSizeEocd
2892
+ combineSizeEocd,
2893
+ fetch
2743
2894
  });
2744
2895
  }
2745
2896
 
@@ -2758,7 +2909,10 @@ async function initHttpReader(httpReader, sendRequest, getRequestData) {
2758
2909
  throw new Error(ERR_HTTP_RANGE);
2759
2910
  } else {
2760
2911
  if (combineSizeEocd) {
2761
- httpReader.eocdCache = new Uint8Array(await response.arrayBuffer());
2912
+ const eocdCache = new Uint8Array(await response.arrayBuffer());
2913
+ if (response.status == 206 && eocdCache.length == END_OF_CENTRAL_DIR_LENGTH) {
2914
+ httpReader.eocdCache = eocdCache;
2915
+ }
2762
2916
  }
2763
2917
  let contentSize;
2764
2918
  const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
@@ -2804,7 +2958,18 @@ async function readUint8ArrayHttpReader(httpReader, index, length, sendRequest,
2804
2958
  if (response.status != 206) {
2805
2959
  throw new Error(ERR_HTTP_RANGE);
2806
2960
  }
2807
- return new Uint8Array(await response.arrayBuffer());
2961
+ const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
2962
+ if (contentRangeHeader) {
2963
+ const rangeStart = Number(contentRangeHeader.trim().split(/[\s-]+/)[1]);
2964
+ if (!Number.isNaN(rangeStart) && rangeStart != index) {
2965
+ throw new Error(ERR_HTTP_RANGE);
2966
+ }
2967
+ }
2968
+ const data = new Uint8Array(await response.arrayBuffer());
2969
+ if (data.length != length) {
2970
+ throw new Error(ERR_HTTP_RANGE);
2971
+ }
2972
+ return data;
2808
2973
  }
2809
2974
  } else {
2810
2975
  const { data } = httpReader;
@@ -2841,9 +3006,9 @@ async function getXMLHttpRequestData(httpReader) {
2841
3006
  async function getRequestData(httpReader, sendRequest) {
2842
3007
  const response = await sendRequest(HTTP_METHOD_GET, httpReader, getHeaders(httpReader));
2843
3008
  httpReader.data = new Uint8Array(await response.arrayBuffer());
2844
- if (!httpReader.size) {
2845
- httpReader.size = httpReader.data.length;
2846
- }
3009
+ // the downloaded content is authoritative, e.g. the Content-Length response header
3010
+ // of the HEAD request can be the encoded size when the content is compressed
3011
+ httpReader.size = httpReader.data.length;
2847
3012
  }
2848
3013
 
2849
3014
  async function getContentLength(httpReader, sendRequest, getRequestData) {
@@ -2852,7 +3017,7 @@ async function getContentLength(httpReader, sendRequest, getRequestData) {
2852
3017
  } else {
2853
3018
  const response = await sendRequest(HTTP_METHOD_HEAD, httpReader, getHeaders(httpReader));
2854
3019
  const contentLength = response.headers.get(HTTP_HEADER_CONTENT_LENGTH);
2855
- if (contentLength) {
3020
+ if (contentLength && !response.headers.get(HTTP_HEADER_CONTENT_ENCODING)) {
2856
3021
  httpReader.size = Number(contentLength);
2857
3022
  } else {
2858
3023
  await getRequestData(httpReader, httpReader.options);
@@ -2860,8 +3025,8 @@ async function getContentLength(httpReader, sendRequest, getRequestData) {
2860
3025
  }
2861
3026
  }
2862
3027
 
2863
- async function sendFetchRequest(method, { options, url }, headers) {
2864
- const response = await fetch(url, Object.assign({}, options, { method, headers }));
3028
+ async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
3029
+ const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
2865
3030
  if (response.status < 400) {
2866
3031
  return response;
2867
3032
  } else {
@@ -2907,7 +3072,8 @@ class HttpReader extends Reader {
2907
3072
  super();
2908
3073
  Object.assign(this, {
2909
3074
  url,
2910
- reader: options.useXHR ? new XHRReader(url, options) : new FetchReader(url, options)
3075
+ // an explicit fetch implementation takes precedence over useXHR
3076
+ reader: options.useXHR && !options.fetch ? new XHRReader(url, options) : new FetchReader(url, options)
2911
3077
  });
2912
3078
  }
2913
3079
 
@@ -2932,8 +3098,7 @@ class HttpReader extends Reader {
2932
3098
  class HttpRangeReader extends HttpReader {
2933
3099
 
2934
3100
  constructor(url, options = {}) {
2935
- options.useRangeHeader = true;
2936
- super(url, options);
3101
+ super(url, Object.assign({}, options, { useRangeHeader: true }));
2937
3102
  }
2938
3103
  }
2939
3104
 
@@ -3007,7 +3172,7 @@ class SplitDataReader extends Reader {
3007
3172
  reader.lastDiskNumber = 0;
3008
3173
  reader.lastDiskOffset = 0;
3009
3174
  await Promise.all(readers.map(async (diskReader, indexDiskReader) => {
3010
- await diskReader.init();
3175
+ await initStream(diskReader);
3011
3176
  if (indexDiskReader != readers.length - 1) {
3012
3177
  reader.lastDiskOffset += diskReader.size;
3013
3178
  }
@@ -3091,14 +3256,26 @@ class SplitDataWriter extends Stream {
3091
3256
  writer.diskOffset += diskSourceWriter.size;
3092
3257
  writer.diskNumber++;
3093
3258
  diskWriter = null;
3094
- await this.write(chunk.subarray(availableSize));
3259
+ // the next disk is not opened yet but its space is available; leaving a
3260
+ // stale value here would force a new disk for every subsequent write
3261
+ writer.availableSize = writer.maxSize;
3262
+ if (chunk.length > availableSize) {
3263
+ await this.write(chunk.subarray(availableSize));
3264
+ }
3095
3265
  } else {
3096
3266
  await writeChunk(chunk);
3097
3267
  }
3098
3268
  },
3099
3269
  async close() {
3100
- await diskWriter.ready;
3101
- await closeDisk();
3270
+ if (diskWriter) {
3271
+ await diskWriter.ready;
3272
+ await closeDisk();
3273
+ }
3274
+ },
3275
+ async abort(reason) {
3276
+ if (diskWriter) {
3277
+ await diskWriter.abort(reason);
3278
+ }
3102
3279
  }
3103
3280
  });
3104
3281
  Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
@@ -3113,7 +3290,6 @@ class SplitDataWriter extends Stream {
3113
3290
  await diskWriter.ready;
3114
3291
  await diskWriter.write(chunk);
3115
3292
  diskSourceWriter.size += chunkLength;
3116
- writer.size += chunkLength;
3117
3293
  writer.availableSize -= chunkLength;
3118
3294
  }
3119
3295
  }
@@ -3213,7 +3389,7 @@ function readUint8Array(reader, offset, size, diskNumber) {
3213
3389
 
3214
3390
  /* global TextDecoder */
3215
3391
 
3216
- const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3392
+ const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3217
3393
  const VALID_CP437 = CP437.length == 256;
3218
3394
 
3219
3395
  function decodeCP437(stringValue) {
@@ -3261,7 +3437,8 @@ function decodeText(value, encoding) {
3261
3437
  if (encoding && encoding.trim().toLowerCase() == "cp437") {
3262
3438
  return decodeCP437(value);
3263
3439
  } else {
3264
- return new TextDecoder(encoding).decode(value);
3440
+ // ignoreBOM keeps a leading U+FEFF in filenames/comments instead of dropping it
3441
+ return new TextDecoder(encoding, { ignoreBOM: true }).decode(value);
3265
3442
  }
3266
3443
  }
3267
3444
 
@@ -3438,6 +3615,7 @@ const OPTION_SIGNAL = "signal";
3438
3615
  const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
3439
3616
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
3440
3617
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
3618
+ const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
3441
3619
  const OPTION_CHECK_SIGNATURE = "checkSignature";
3442
3620
  const OPTION_USE_WEB_WORKERS = "useWebWorkers";
3443
3621
  const OPTION_USE_COMPRESSION_STREAM = "useCompressionStream";
@@ -3495,12 +3673,16 @@ const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
3495
3673
  const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
3496
3674
  const ERR_ENCRYPTED = "File contains encrypted entry";
3497
3675
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
3498
- const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
3676
+ const ERR_UNSUPPORTED_COMPRESSION$1 = "Compression method not supported";
3499
3677
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
3500
3678
  const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
3679
+ const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
3501
3680
  const CHARSET_UTF8 = "utf-8";
3502
3681
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
3503
3682
  const CHARSET_CP437 = "cp437";
3683
+ // bits of the general purpose flag that change how an entry is interpreted; the level bits (1-2) are excluded
3684
+ // because they are informative only
3685
+ const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
3504
3686
  const ZIP64_PROPERTIES = [
3505
3687
  [PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
3506
3688
  [PROPERTY_NAME_COMPRESSED_SIZE, MAX_32_BITS],
@@ -3525,7 +3707,7 @@ class ZipReader {
3525
3707
  reader: new GenericReader(reader),
3526
3708
  options,
3527
3709
  config: getConfiguration(),
3528
- readRanges: []
3710
+ readRanges: new Map()
3529
3711
  });
3530
3712
  }
3531
3713
 
@@ -3558,21 +3740,30 @@ class ZipReader {
3558
3740
  const commentOffset = endOfDirectoryInfo.offset;
3559
3741
  const commentLength = getUint16(endOfDirectoryView, 20);
3560
3742
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
3743
+ const checkAmbiguity = getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY);
3744
+ if (checkAmbiguity && appendedDataOffset != reader.size) {
3745
+ throwAmbiguousArchive("appended data");
3746
+ }
3561
3747
  let lastDiskNumber = getUint16(endOfDirectoryView, 4);
3562
3748
  const expectedLastDiskNumber = reader.lastDiskNumber || 0;
3563
3749
  let diskNumber = getUint16(endOfDirectoryView, 6);
3564
- let filesLength = getUint16(endOfDirectoryView, 8);
3750
+ let filesLength = getUint16(endOfDirectoryView, 10);
3565
3751
  let prependedDataLength = 0;
3566
- let startOffset = 0;
3752
+ let startOffset;
3753
+ let zip64EndOfDirectory;
3567
3754
  if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
3568
- const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH);
3755
+ const endOfDirectoryLocatorArray = endOfDirectoryInfo.offset >= ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH ?
3756
+ await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH) :
3757
+ new Uint8Array();
3569
3758
  const endOfDirectoryLocatorView = getDataView$1(endOfDirectoryLocatorArray);
3570
- if (getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3759
+ if (endOfDirectoryLocatorArray.length == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH &&
3760
+ getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3571
3761
  directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8);
3572
3762
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3573
3763
  let endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3574
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
3575
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3764
+ const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH - (reader.lastDiskOffset || 0);
3765
+ if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
3766
+ directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
3576
3767
  const originalDirectoryDataOffset = directoryDataOffset;
3577
3768
  directoryDataOffset = expectedDirectoryDataOffset;
3578
3769
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3581,24 +3772,36 @@ class ZipReader {
3581
3772
  endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3582
3773
  endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3583
3774
  }
3584
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3775
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3585
3776
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
3586
3777
  }
3778
+ zip64EndOfDirectory = true;
3587
3779
  if (lastDiskNumber == MAX_16_BITS) {
3588
3780
  lastDiskNumber = getUint32(endOfDirectoryView, 16);
3781
+ } else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
3782
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3589
3783
  }
3590
3784
  if (diskNumber == MAX_16_BITS) {
3591
3785
  diskNumber = getUint32(endOfDirectoryView, 20);
3786
+ } else if (checkAmbiguity && diskNumber != getUint32(endOfDirectoryView, 20)) {
3787
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3592
3788
  }
3593
3789
  if (filesLength == MAX_16_BITS) {
3594
3790
  filesLength = getBigUint64(endOfDirectoryView, 32);
3791
+ } else if (checkAmbiguity && filesLength != getBigUint64(endOfDirectoryView, 32)) {
3792
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3595
3793
  }
3596
3794
  if (directoryDataLength == MAX_32_BITS) {
3597
3795
  directoryDataLength = getBigUint64(endOfDirectoryView, 40);
3796
+ } else if (checkAmbiguity && directoryDataLength != getBigUint64(endOfDirectoryView, 40)) {
3797
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3598
3798
  }
3599
- directoryDataOffset -= directoryDataLength;
3799
+ directoryDataOffset = getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
3600
3800
  }
3601
3801
  }
3802
+ const declaredDirectoryDataLength = directoryDataLength;
3803
+ const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
3804
+ (zip64EndOfDirectory ? ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
3602
3805
  if (directoryDataOffset >= reader.size) {
3603
3806
  prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
3604
3807
  directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
@@ -3613,8 +3816,11 @@ class ZipReader {
3613
3816
  let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3614
3817
  let directoryView = getDataView$1(directoryArray);
3615
3818
  if (directoryDataLength) {
3616
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength;
3617
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3819
+ if (directoryArray.length < 4) {
3820
+ throw new Error(ERR_BAD_FORMAT);
3821
+ }
3822
+ const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength - (reader.lastDiskOffset || 0);
3823
+ if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
3618
3824
  const originalDirectoryDataOffset = directoryDataOffset;
3619
3825
  directoryDataOffset = expectedDirectoryDataOffset;
3620
3826
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3624,8 +3830,8 @@ class ZipReader {
3624
3830
  directoryView = getDataView$1(directoryArray);
3625
3831
  }
3626
3832
  }
3627
- const expectedDirectoryDataLength = endOfDirectoryInfo.offset - directoryDataOffset - (reader.lastDiskOffset || 0);
3628
- if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0) {
3833
+ const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset - (reader.lastDiskOffset || 0);
3834
+ if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
3629
3835
  directoryDataLength = expectedDirectoryDataLength;
3630
3836
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3631
3837
  directoryView = getDataView$1(directoryArray);
@@ -3633,16 +3839,19 @@ class ZipReader {
3633
3839
  if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
3634
3840
  throw new Error(ERR_BAD_FORMAT);
3635
3841
  }
3842
+ startOffset = directoryDataOffset;
3636
3843
  const filenameEncoding = getOptionValue$1(zipReader, options, OPTION_FILENAME_ENCODING);
3637
3844
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
3845
+ const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
3846
+ let duplicateFilename;
3638
3847
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
3639
3848
  const fileEntry = new ZipEntry$1(reader, config, zipReader.options);
3640
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3849
+ if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3641
3850
  throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
3642
3851
  }
3643
3852
  readCommonHeader(fileEntry, directoryView, offset + 6);
3644
3853
  const languageEncodingFlag = Boolean(fileEntry.bitFlag.languageEncodingFlag);
3645
- const filenameOffset = offset + 46;
3854
+ const filenameOffset = offset + CENTRAL_FILE_HEADER_LENGTH;
3646
3855
  const extraFieldOffset = filenameOffset + fileEntry.filenameLength;
3647
3856
  const commentOffset = extraFieldOffset + fileEntry.extraFieldLength;
3648
3857
  const versionMadeBy = getUint16(directoryView, offset + 4);
@@ -3663,7 +3872,7 @@ class ZipReader {
3663
3872
  directory: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_DIR_MASK),
3664
3873
  archive: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_ARCHIVE_MASK)
3665
3874
  };
3666
- const offsetFileEntry = getUint32(directoryView, offset + 42) + prependedDataLength;
3875
+ const offsetFileEntry = getUint32(directoryView, offset + 42);
3667
3876
  const decode = getOptionValue$1(zipReader, options, OPTION_DECODE_TEXT) || decodeText;
3668
3877
  const rawFilenameEncoding = filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437;
3669
3878
  const rawCommentEncoding = commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437;
@@ -3676,6 +3885,7 @@ class ZipReader {
3676
3885
  comment = decodeText(rawComment, rawCommentEncoding);
3677
3886
  }
3678
3887
  Object.assign(fileEntry, {
3888
+ index: indexFile,
3679
3889
  versionMadeBy,
3680
3890
  msDosCompatible,
3681
3891
  compressedSize: 0,
@@ -3695,8 +3905,15 @@ class ZipReader {
3695
3905
  filename,
3696
3906
  comment
3697
3907
  });
3698
- startOffset = Math.max(offsetFileEntry, startOffset);
3699
3908
  readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
3909
+ fileEntry.offset += prependedDataLength;
3910
+ startOffset = Math.min(fileEntry.offset, startOffset);
3911
+ if (checkAmbiguity) {
3912
+ if (filenames.has(fileEntry.filename)) {
3913
+ duplicateFilename = true;
3914
+ }
3915
+ filenames.add(fileEntry.filename);
3916
+ }
3700
3917
  const unixExternalUpper = (fileEntry.externalFileAttributes >> 16) & MAX_16_BITS;
3701
3918
  if (fileEntry.unixMode === UNDEFINED_VALUE && (unixExternalUpper & (FILE_ATTR_UNIX_DEFAULT_MASK | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_TYPE_DIR)) != 0) {
3702
3919
  fileEntry.unixMode = unixExternalUpper;
@@ -3717,7 +3934,7 @@ class ZipReader {
3717
3934
  internalFileAttribute: fileEntry.internalFileAttributes,
3718
3935
  externalFileAttribute: fileEntry.externalFileAttributes,
3719
3936
  executable,
3720
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
3937
+ directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (fileEntry.filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
3721
3938
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
3722
3939
  });
3723
3940
  const entry = new Entry(fileEntry);
@@ -3740,6 +3957,15 @@ class ZipReader {
3740
3957
  }
3741
3958
  yield entry;
3742
3959
  }
3960
+ if (checkAmbiguity && offset != declaredDirectoryDataLength) {
3961
+ throwAmbiguousArchive("trailing central directory data");
3962
+ }
3963
+ if (duplicateFilename) {
3964
+ throwAmbiguousArchive("duplicate filename");
3965
+ }
3966
+ if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > 0))) {
3967
+ throwAmbiguousArchive("prepended data");
3968
+ }
3743
3969
  const extractPrependedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
3744
3970
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
3745
3971
  if (extractPrependedData) {
@@ -3779,9 +4005,21 @@ class ZipReaderStream {
3779
4005
  readable: (function () {
3780
4006
  const { readable, writable } = new TransformStream();
3781
4007
  if (value.getData) {
3782
- value.getData(writable);
4008
+ getData();
3783
4009
  return readable;
3784
4010
  }
4011
+
4012
+ async function getData() {
4013
+ try {
4014
+ await value.getData(writable);
4015
+ } catch (error) {
4016
+ try {
4017
+ await writable.abort(error);
4018
+ } catch {
4019
+ // ignored
4020
+ }
4021
+ }
4022
+ }
3785
4023
  })()
3786
4024
  };
3787
4025
  delete chunk.getData;
@@ -3806,6 +4044,7 @@ let ZipEntry$1 = class ZipEntry {
3806
4044
  const zipEntry = this;
3807
4045
  const {
3808
4046
  reader,
4047
+ index,
3809
4048
  offset,
3810
4049
  diskNumberStart,
3811
4050
  extraFieldAES,
@@ -3831,27 +4070,42 @@ let ZipEntry$1 = class ZipEntry {
3831
4070
  rawPassword = rawPassword && rawPassword.length && rawPassword;
3832
4071
  if (extraFieldAES) {
3833
4072
  if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
3834
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4073
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3835
4074
  }
3836
4075
  }
3837
4076
  if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64) && !passThrough) {
3838
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4077
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3839
4078
  }
3840
- if (getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
4079
+ if (dataArray.length < HEADER_SIZE || getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
3841
4080
  throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
3842
4081
  }
3843
4082
  readCommonHeader(localDirectory, dataView, 4);
3844
4083
  const {
3845
4084
  extraFieldLength,
3846
- filenameLength,
3847
- lastAccessDate,
3848
- creationDate
4085
+ filenameLength
3849
4086
  } = localDirectory;
3850
- localDirectory.rawExtraField = extraFieldLength ?
3851
- await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
3852
- new Uint8Array();
4087
+ const checkAmbiguity = getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY);
4088
+ let rawLocalFilename = new Uint8Array();
4089
+ if (checkAmbiguity && (filenameLength || extraFieldLength)) {
4090
+ const trailingDataArray = await readUint8Array(reader, offset + HEADER_SIZE, filenameLength + extraFieldLength, diskNumberStart);
4091
+ rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
4092
+ localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
4093
+ } else {
4094
+ localDirectory.rawExtraField = extraFieldLength ?
4095
+ await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
4096
+ new Uint8Array();
4097
+ }
3853
4098
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
3854
- Object.assign(fileEntry, { lastAccessDate, creationDate });
4099
+ if (checkAmbiguity) {
4100
+ checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
4101
+ }
4102
+ const { lastAccessDate, creationDate } = localDirectory;
4103
+ if (lastAccessDate) {
4104
+ fileEntry.lastAccessDate = lastAccessDate;
4105
+ }
4106
+ if (creationDate) {
4107
+ fileEntry.creationDate = creationDate;
4108
+ }
3855
4109
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
3856
4110
  const zipCrypto = encrypted && !extraFieldAES;
3857
4111
  if (!passThrough) {
@@ -3897,7 +4151,7 @@ let ZipEntry$1 = class ZipEntry {
3897
4151
  outputSize: passThrough ? compressedSize : uncompressedSize,
3898
4152
  signature,
3899
4153
  compressed: compressionMethod != 0 && !passThrough,
3900
- encrypted: zipEntry.encrypted && !passThrough,
4154
+ encrypted,
3901
4155
  useWebWorkers: getOptionValue$1(zipEntry, options, OPTION_USE_WEB_WORKERS),
3902
4156
  useCompressionStream,
3903
4157
  transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
@@ -3911,6 +4165,7 @@ let ZipEntry$1 = class ZipEntry {
3911
4165
  await detectOverlappingEntry({
3912
4166
  reader,
3913
4167
  fileEntry,
4168
+ index,
3914
4169
  offset,
3915
4170
  diskNumberStart,
3916
4171
  signature,
@@ -4013,7 +4268,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
4013
4268
  directory.extraFieldUnicodeComment = extraFieldUnicodeComment;
4014
4269
  }
4015
4270
  const extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES);
4016
- if (extraFieldAES) {
4271
+ if (extraFieldAES && extraFieldAES.data.length >= 7) {
4017
4272
  readExtraFieldAES(extraFieldAES, directory, compressionMethod);
4018
4273
  directory.extraFieldAES = extraFieldAES;
4019
4274
  } else {
@@ -4050,19 +4305,23 @@ function readExtraFieldZip64(extraFieldZip64, directory) {
4050
4305
  directory.zip64 = true;
4051
4306
  const extraFieldView = getDataView$1(extraFieldZip64.data);
4052
4307
  const missingProperties = ZIP64_PROPERTIES.filter(([propertyName, max]) => directory[propertyName] == max);
4308
+ const requiredLength = missingProperties.reduce((length, [, max]) => length + ZIP64_EXTRACTION[max].bytes, 0);
4309
+ if (extraFieldZip64.data.length < requiredLength) {
4310
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4311
+ }
4053
4312
  for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
4054
4313
  const [propertyName, max] = missingProperties[indexMissingProperty];
4055
- if (directory[propertyName] == max) {
4056
- const extraction = ZIP64_EXTRACTION[max];
4057
- directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4058
- offset += extraction.bytes;
4059
- } else if (extraFieldZip64[propertyName]) {
4060
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4061
- }
4314
+ const extraction = ZIP64_EXTRACTION[max];
4315
+ directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4316
+ offset += extraction.bytes;
4062
4317
  }
4063
4318
  }
4064
4319
 
4065
4320
  function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) {
4321
+ if (extraFieldUnicode.data.length < 5) {
4322
+ extraFieldUnicode.valid = false;
4323
+ return;
4324
+ }
4066
4325
  const extraFieldView = getDataView$1(extraFieldUnicode.data);
4067
4326
  const crc32 = new Crc32();
4068
4327
  crc32.append(fileEntry[rawPropertyName]);
@@ -4135,32 +4394,30 @@ function readExtraFieldNTFS(extraFieldNTFS, directory) {
4135
4394
  function readExtraFieldUnix(extraField, directory, isInfoZip) {
4136
4395
  try {
4137
4396
  const view = getDataView$1(new Uint8Array(extraField.data));
4138
- let offset = 0;
4139
- const version = getUint8(view, offset++);
4140
- const uidSize = getUint8(view, offset++);
4141
- const uidBytes = extraField.data.subarray(offset, offset + uidSize);
4142
- offset += uidSize;
4143
- const uid = unpackUnixId(uidBytes);
4144
- const gidSize = getUint8(view, offset++);
4145
- const gidBytes = extraField.data.subarray(offset, offset + gidSize);
4146
- offset += gidSize;
4147
- const gid = unpackUnixId(gidBytes);
4148
- let unixMode = UNDEFINED_VALUE;
4149
- if (!isInfoZip && offset + 2 <= extraField.data.length) {
4150
- const base = extraField.data;
4151
- const modeView = new DataView(base.buffer, base.byteOffset + offset, 2);
4152
- unixMode = modeView.getUint16(0, true);
4153
- }
4154
- Object.assign(extraField, { version, uid, gid, unixMode });
4397
+ let uid, gid;
4398
+ if (isInfoZip) {
4399
+ // Info-ZIP New Unix "ux" field (0x7875): version + variable-length uid/gid
4400
+ let offset = 0;
4401
+ const version = getUint8(view, offset++);
4402
+ const uidSize = getUint8(view, offset++);
4403
+ uid = unpackUnixId(extraField.data.subarray(offset, offset + uidSize));
4404
+ offset += uidSize;
4405
+ const gidSize = getUint8(view, offset++);
4406
+ gid = unpackUnixId(extraField.data.subarray(offset, offset + gidSize));
4407
+ Object.assign(extraField, { version, uid, gid });
4408
+ } else if (extraField.data.length >= 4) {
4409
+ // Info-ZIP Unix "Ux" field (0x7855): fixed 2-byte uid + gid (the file mode, if any, is
4410
+ // carried in the external file attributes, not here)
4411
+ uid = getUint16(view, 0);
4412
+ gid = getUint16(view, 2);
4413
+ Object.assign(extraField, { uid, gid });
4414
+ }
4155
4415
  if (uid !== UNDEFINED_VALUE) {
4156
4416
  directory.uid = uid;
4157
4417
  }
4158
4418
  if (gid !== UNDEFINED_VALUE) {
4159
4419
  directory.gid = gid;
4160
4420
  }
4161
- if (unixMode !== UNDEFINED_VALUE) {
4162
- directory.unixMode = unixMode;
4163
- }
4164
4421
  } catch {
4165
4422
  // ignored
4166
4423
  }
@@ -4174,6 +4431,9 @@ function unpackUnixId(bytes) {
4174
4431
  }
4175
4432
 
4176
4433
  function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory) {
4434
+ if (!extraFieldExtendedTimestamp.data.length) {
4435
+ return;
4436
+ }
4177
4437
  const extraFieldView = getDataView$1(extraFieldExtendedTimestamp.data);
4178
4438
  const flags = getUint8(extraFieldView, 0);
4179
4439
  const timeProperties = [];
@@ -4199,7 +4459,8 @@ function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory,
4199
4459
  timeProperties.forEach((propertyName, indexProperty) => {
4200
4460
  if (extraFieldExtendedTimestamp.data.length >= offset + 4) {
4201
4461
  const time = getUint32(extraFieldView, offset);
4202
- directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date(time * 1000);
4462
+ // the extended timestamp is a signed 32-bit time_t value
4463
+ directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date((time | 0) * 1000);
4203
4464
  const rawPropertyName = timeRawProperties[indexProperty];
4204
4465
  extraFieldExtendedTimestamp[rawPropertyName] = time;
4205
4466
  }
@@ -4210,6 +4471,7 @@ function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory,
4210
4471
  async function detectOverlappingEntry({
4211
4472
  reader,
4212
4473
  fileEntry,
4474
+ index,
4213
4475
  offset,
4214
4476
  diskNumberStart,
4215
4477
  signature,
@@ -4221,10 +4483,9 @@ async function detectOverlappingEntry({
4221
4483
  readRanges
4222
4484
  }) {
4223
4485
  let diskOffset = 0;
4224
- if (diskNumberStart) {
4225
- for (let indexReader = 0; indexReader < diskNumberStart; indexReader++) {
4226
- const diskReader = reader.readers[indexReader];
4227
- diskOffset += diskReader.size;
4486
+ if (diskNumberStart && reader.readers) {
4487
+ for (let indexReader = 0; indexReader < Math.min(diskNumberStart, reader.readers.length); indexReader++) {
4488
+ diskOffset += reader.readers[indexReader].size;
4228
4489
  }
4229
4490
  }
4230
4491
  let dataDescriptorLength = 0;
@@ -4237,7 +4498,8 @@ async function detectOverlappingEntry({
4237
4498
  }
4238
4499
  if (dataDescriptorLength) {
4239
4500
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, diskNumberStart);
4240
- const dataDescriptorSignature = getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4501
+ const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
4502
+ getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4241
4503
  if (dataDescriptorSignature) {
4242
4504
  const readSignature = getUint32(getDataView$1(dataDescriptorArray), 4);
4243
4505
  let readCompressedSize;
@@ -4262,14 +4524,14 @@ async function detectOverlappingEntry({
4262
4524
  end: diskOffset + dataOffset + compressedSize + dataDescriptorLength,
4263
4525
  fileEntry
4264
4526
  };
4265
- for (const otherRange of readRanges) {
4266
- if (otherRange.fileEntry != fileEntry && range.start >= otherRange.start && range.start < otherRange.end) {
4527
+ for (const [otherIndex, otherRange] of readRanges) {
4528
+ if (otherIndex != index && range.start < otherRange.end && otherRange.start < range.end) {
4267
4529
  const error = new Error(ERR_OVERLAPPING_ENTRY);
4268
4530
  error.overlappingEntry = otherRange.fileEntry;
4269
4531
  throw error;
4270
4532
  }
4271
4533
  }
4272
- readRanges.push(range);
4534
+ readRanges.set(index, range);
4273
4535
  }
4274
4536
 
4275
4537
  async function seekSignature(reader, signature, startOffset, minimumBytes, maximumLength) {
@@ -4294,6 +4556,35 @@ async function seekSignature(reader, signature, startOffset, minimumBytes, maxim
4294
4556
  }
4295
4557
  }
4296
4558
 
4559
+ function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
4560
+ const { rawFilename } = zipEntry;
4561
+ if (rawLocalFilename.length != rawFilename.length ||
4562
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
4563
+ throwAmbiguousArchive("mismatched local file header (filename)");
4564
+ }
4565
+ if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
4566
+ throwAmbiguousArchive("mismatched local file header (general purpose bit flag)");
4567
+ }
4568
+ if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
4569
+ throwAmbiguousArchive("mismatched local file header (compression method)");
4570
+ }
4571
+ // when the data descriptor flag is set, the local signature and sizes are zeroed out; all-zero values are
4572
+ // also tolerated when the flag is clear because some tools produce them (streaming writers predating bit 3)
4573
+ if (!localDirectory.bitFlag.dataDescriptor &&
4574
+ (localDirectory.signature || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
4575
+ (localDirectory.signature != zipEntry.signature ||
4576
+ localDirectory.compressedSize != zipEntry.compressedSize ||
4577
+ localDirectory.uncompressedSize != zipEntry.uncompressedSize)) {
4578
+ throwAmbiguousArchive("mismatched local file header (signature or sizes)");
4579
+ }
4580
+ }
4581
+
4582
+ function throwAmbiguousArchive(reason) {
4583
+ const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
4584
+ error.reason = reason;
4585
+ throw error;
4586
+ }
4587
+
4297
4588
  function getOptionValue$1(zipReader, options, name) {
4298
4589
  return options[name] === UNDEFINED_VALUE ? zipReader.options[name] : options[name];
4299
4590
  }
@@ -4332,7 +4623,7 @@ function setUint32$1(view, offset, value) {
4332
4623
  }
4333
4624
 
4334
4625
  function getDataView$1(array) {
4335
- return new DataView(array.buffer);
4626
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
4336
4627
  }
4337
4628
 
4338
4629
  /*
@@ -4372,13 +4663,19 @@ const ERR_INVALID_VERSION = "Version exceeds 65535";
4372
4663
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
4373
4664
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
4374
4665
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
4666
+ // same message as the constant exported by zip-reader.js
4667
+ const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
4668
+ const MIN_UNIX_TIME = -2147483648;
4669
+ const MAX_UNIX_TIME = 2147483647;
4375
4670
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
4376
4671
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
4672
+ const ERR_UNDEFINED_READER = "Undefined reader";
4377
4673
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
4378
4674
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
4379
4675
  const ERR_INVALID_GID = "Invalid gid (must be integer 0..2^32-1)";
4380
4676
  const ERR_INVALID_UNIX_MODE = "Invalid UNIX mode (must be integer 0..65535)";
4381
4677
  const ERR_INVALID_UNIX_EXTRA_FIELD_TYPE = "Invalid unixExtraFieldType (must be 'infozip' or 'unix')";
4678
+ const ERR_INVALID_UNIX_ID_SIZE = "uid/gid must be 0..65535 for unixExtraFieldType 'unix' (use 'infozip' for larger ids)";
4382
4679
  const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be integer 0..255)";
4383
4680
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
4384
4681
 
@@ -4404,9 +4701,10 @@ class ZipWriter {
4404
4701
  files: new Map(),
4405
4702
  filenames: new Set(),
4406
4703
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
4407
- pendingEntriesSize: 0,
4704
+ initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
4408
4705
  pendingAddFileCalls: new Set(),
4409
- bufferedWrites: 0
4706
+ bufferedWrites: 0,
4707
+ lastFileEntry: UNDEFINED_VALUE
4410
4708
  });
4411
4709
  }
4412
4710
 
@@ -4415,17 +4713,18 @@ class ZipWriter {
4415
4713
  throw new Error(ERR_ZIP_NOT_EMPTY);
4416
4714
  }
4417
4715
  reader = new GenericReader(reader);
4716
+ await initStream(reader);
4418
4717
  const zipReader = new ZipReader(reader.readable);
4419
4718
  const entries = await zipReader.getEntries();
4420
4719
  await zipReader.close();
4720
+ await initStream(this.writer);
4421
4721
  await reader.readable.pipeTo(this.writer.writable, { preventClose: true, preventAbort: true });
4422
4722
  this.writer.size = this.offset = reader.size;
4423
4723
  this.filenames = new Set(entries.map(entry => entry.filename));
4424
4724
  this.files = new Map(entries.map(entry => {
4425
4725
  const {
4426
4726
  version,
4427
- compressionMethod,
4428
- lastModDate,
4727
+ rawLastModDate,
4429
4728
  lastAccessDate,
4430
4729
  creationDate,
4431
4730
  rawFilename,
@@ -4438,6 +4737,7 @@ class ZipWriter {
4438
4737
  zip64
4439
4738
  } = entry;
4440
4739
  let {
4740
+ compressionMethod,
4441
4741
  rawExtraFieldZip64,
4442
4742
  rawExtraFieldAES,
4443
4743
  rawExtraFieldExtendedTimestamp,
@@ -4450,31 +4750,39 @@ class ZipWriter {
4450
4750
  rawExtraFieldAES = rawExtraFieldAES || new Uint8Array();
4451
4751
  rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || new Uint8Array();
4452
4752
  rawExtraFieldNTFS = rawExtraFieldNTFS || new Uint8Array();
4453
- rawExtraFieldUnix = entry.rawExtraFieldUnix || new Uint8Array();
4753
+ rawExtraFieldUnix = rawExtraFieldUnix || new Uint8Array();
4454
4754
  rawExtraField = rawExtraField || new Uint8Array();
4755
+ if (entry.extraFieldAES) {
4756
+ compressionMethod = COMPRESSION_METHOD_AES;
4757
+ }
4455
4758
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
4456
- const zip64UncompressedSize = zip64 && uncompressedSize > MAX_32_BITS;
4457
- const zip64CompressedSize = zip64 && compressedSize > MAX_32_BITS;
4759
+ const zip64UncompressedSize = zip64 && uncompressedSize >= MAX_32_BITS;
4760
+ const zip64CompressedSize = zip64 && compressedSize >= MAX_32_BITS;
4761
+ const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
4458
4762
  const {
4459
4763
  headerArray,
4460
4764
  headerView
4461
4765
  } = getHeaderArrayData({
4462
4766
  version,
4463
- bitFlag: getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod),
4767
+ bitFlag: bitFlagValue,
4464
4768
  compressionMethod,
4465
4769
  uncompressedSize,
4466
4770
  compressedSize,
4467
- lastModDate,
4771
+ rawLastModDate,
4468
4772
  rawFilename,
4469
4773
  zip64CompressedSize,
4470
4774
  zip64UncompressedSize,
4471
4775
  extraFieldLength
4472
4776
  });
4777
+ const { signature } = entry;
4778
+ if (signature !== UNDEFINED_VALUE) {
4779
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, signature);
4780
+ }
4473
4781
  Object.assign(entry, {
4474
4782
  zip64UncompressedSize,
4475
4783
  zip64CompressedSize,
4476
- zip64Offset: zip64 && this.offset - diskOffset > MAX_32_BITS,
4477
- zip64DiskNumberStart: zip64 && diskNumber > MAX_16_BITS,
4784
+ zip64Offset: zip64 && this.offset - diskOffset >= MAX_32_BITS,
4785
+ zip64DiskNumberStart: zip64 && diskNumber >= MAX_16_BITS,
4478
4786
  rawExtraFieldZip64,
4479
4787
  rawExtraFieldAES,
4480
4788
  rawExtraFieldExtendedTimestamp,
@@ -4492,6 +4800,7 @@ class ZipWriter {
4492
4800
 
4493
4801
  async add(name = "", reader, options = {}) {
4494
4802
  const zipWriter = this;
4803
+ options = Object.assign({}, options);
4495
4804
  const {
4496
4805
  pendingAddFileCalls,
4497
4806
  config
@@ -4502,17 +4811,24 @@ class ZipWriter {
4502
4811
  await new Promise(resolve => pendingEntries.push(resolve));
4503
4812
  }
4504
4813
  let promiseAddFile;
4814
+ let nameAdded;
4505
4815
  try {
4506
4816
  name = name.trim();
4817
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
4818
+ name += DIRECTORY_SIGNATURE;
4819
+ }
4507
4820
  if (zipWriter.filenames.has(name)) {
4508
4821
  throw new Error(ERR_DUPLICATED_NAME);
4509
4822
  }
4510
4823
  zipWriter.filenames.add(name);
4824
+ nameAdded = true;
4511
4825
  promiseAddFile = addFile(zipWriter, name, reader, options);
4512
4826
  pendingAddFileCalls.add(promiseAddFile);
4513
4827
  return await promiseAddFile;
4514
4828
  } catch (error) {
4515
- zipWriter.filenames.delete(name);
4829
+ if (nameAdded) {
4830
+ zipWriter.filenames.delete(name);
4831
+ }
4516
4832
  throw error;
4517
4833
  } finally {
4518
4834
  pendingAddFileCalls.delete(promiseAddFile);
@@ -4545,6 +4861,9 @@ class ZipWriter {
4545
4861
  const zipWriter = this;
4546
4862
  const { pendingAddFileCalls, writer } = this;
4547
4863
  const { writable } = writer;
4864
+ if (getLength(comment) > MAX_16_BITS) {
4865
+ throw new Error(ERR_INVALID_COMMENT);
4866
+ }
4548
4867
  while (pendingAddFileCalls.size) {
4549
4868
  await Promise.allSettled(Array.from(pendingAddFileCalls));
4550
4869
  }
@@ -4563,28 +4882,94 @@ class ZipWriterStream {
4563
4882
  const { readable, writable } = new TransformStream();
4564
4883
  this.readable = readable;
4565
4884
  this.zipWriter = new ZipWriter(writable, options);
4885
+ this.pendingAddFileCalls = new Set();
4566
4886
  }
4567
4887
 
4568
4888
  transform(path) {
4889
+ const zipWriter = this.zipWriter;
4890
+ let streamController;
4569
4891
  const { readable, writable } = new TransformStream({
4570
- flush: () => { this.zipWriter.close(); }
4892
+ start(controller) {
4893
+ streamController = controller;
4894
+ },
4895
+ flush: () => void closeArchive()
4571
4896
  });
4572
- this.zipWriter.add(path, readable);
4897
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4573
4898
  return { readable: this.readable, writable };
4899
+
4900
+ async function closeArchive() {
4901
+ try {
4902
+ await zipWriter.close();
4903
+ } catch (error) {
4904
+ try {
4905
+ await zipWriter.writer.writable.abort(error);
4906
+ } catch {
4907
+ // ignored
4908
+ }
4909
+ }
4910
+ }
4574
4911
  }
4575
4912
 
4576
4913
  writable(path) {
4577
- const { readable, writable } = new TransformStream();
4578
- this.zipWriter.add(path, readable);
4914
+ let streamController;
4915
+ const { readable, writable } = new TransformStream({
4916
+ start(controller) {
4917
+ streamController = controller;
4918
+ }
4919
+ });
4920
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4579
4921
  return writable;
4580
4922
  }
4581
4923
 
4582
- close(comment = UNDEFINED_VALUE, options = {}) {
4924
+ async close(comment = UNDEFINED_VALUE, options = {}) {
4925
+ await Promise.all(Array.from(this.pendingAddFileCalls));
4583
4926
  return this.zipWriter.close(comment, options);
4584
4927
  }
4585
4928
  }
4586
4929
 
4930
+ function watchAddFileCall(zipWriterStream, promiseAddFile, onerror) {
4931
+ zipWriterStream.pendingAddFileCalls.add(promiseAddFile);
4932
+ promiseAddFile.catch(error => {
4933
+ try {
4934
+ onerror(error);
4935
+ } catch {
4936
+ // ignored
4937
+ }
4938
+ });
4939
+ }
4940
+
4587
4941
  async function addFile(zipWriter, name, reader, options) {
4942
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
4943
+ ({ name } = attributesInfo);
4944
+ const metadataInfo = resolveMetadata(zipWriter, name, options);
4945
+ const { comment } = metadataInfo;
4946
+ const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
4947
+ zipWriter.files.set(name, UNDEFINED_VALUE);
4948
+ let fileEntry;
4949
+ try {
4950
+ const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
4951
+ ({ reader } = sizesInfo);
4952
+ const { diskOffset, diskNumber } = zipWriter.writer;
4953
+ options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
4954
+ internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
4955
+ externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
4956
+ signature: options[PROPERTY_NAME_SIGNATURE],
4957
+ offset: zipWriter.offset - diskOffset,
4958
+ diskNumberStart: diskNumber
4959
+ });
4960
+ const headerInfo = getHeaderInfo(options);
4961
+ const dataDescriptorInfo = getDataDescriptorInfo(options);
4962
+ const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
4963
+ fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
4964
+ } catch (error) {
4965
+ zipWriter.files.delete(name);
4966
+ throw error;
4967
+ }
4968
+ Object.assign(fileEntry, { name, comment, extraField });
4969
+ return new Entry(fileEntry);
4970
+ }
4971
+
4972
+ function resolveAttributes(zipWriter, name, options) {
4588
4973
  name = name.trim();
4589
4974
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
4590
4975
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
@@ -4592,7 +4977,7 @@ async function addFile(zipWriter, name, reader, options) {
4592
4977
  const uid = getOptionValue(zipWriter, options, PROPERTY_NAME_UID);
4593
4978
  const gid = getOptionValue(zipWriter, options, PROPERTY_NAME_GID);
4594
4979
  let unixMode = getOptionValue(zipWriter, options, PROPERTY_NAME_UNIX_MODE);
4595
- const unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
4980
+ let unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
4596
4981
  let setuid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETUID);
4597
4982
  let setgid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETGID);
4598
4983
  let sticky = getOptionValue(zipWriter, options, PROPERTY_NAME_STICKY);
@@ -4608,6 +4993,13 @@ async function addFile(zipWriter, name, reader, options) {
4608
4993
  if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
4609
4994
  throw new Error(ERR_INVALID_UNIX_EXTRA_FIELD_TYPE);
4610
4995
  }
4996
+ if (unixExtraFieldType === UNIX_EXTRA_FIELD_TYPE &&
4997
+ ((uid !== UNDEFINED_VALUE && uid > MAX_16_BITS) || (gid !== UNDEFINED_VALUE && gid > MAX_16_BITS))) {
4998
+ throw new Error(ERR_INVALID_UNIX_ID_SIZE);
4999
+ }
5000
+ if (unixExtraFieldType === UNDEFINED_VALUE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5001
+ unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE;
5002
+ }
4611
5003
  let msdosAttributesRaw = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW);
4612
5004
  let msdosAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES);
4613
5005
  const hasUnixMetadata = uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE || unixExtraFieldType;
@@ -4678,6 +5070,27 @@ async function addFile(zipWriter, name, reader, options) {
4678
5070
  if (hasMsDosProvided) {
4679
5071
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
4680
5072
  }
5073
+ return {
5074
+ name,
5075
+ resolvedOptions: {
5076
+ versionMadeBy,
5077
+ msDosCompatible,
5078
+ externalFileAttributes,
5079
+ unixExternalUpper,
5080
+ uid,
5081
+ gid,
5082
+ unixMode,
5083
+ unixExtraFieldType,
5084
+ setuid,
5085
+ setgid,
5086
+ sticky,
5087
+ msdosAttributesRaw,
5088
+ msdosAttributes
5089
+ }
5090
+ };
5091
+ }
5092
+
5093
+ function resolveMetadata(zipWriter, name, options) {
4681
5094
  const encode = getOptionValue(zipWriter, options, OPTION_ENCODE_TEXT, encodeText);
4682
5095
  let rawFilename = encode(name);
4683
5096
  if (rawFilename === UNDEFINED_VALUE) {
@@ -4716,10 +5129,14 @@ async function addFile(zipWriter, name, reader, options) {
4716
5129
  const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS, true);
4717
5130
  const bufferedWrite = getOptionValue(zipWriter, options, OPTION_BUFFERED_WRITE);
4718
5131
  const createTempStream = getOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
4719
- const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, false);
5132
+ const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
4720
5133
  const signal = getOptionValue(zipWriter, options, OPTION_SIGNAL);
4721
5134
  const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
4722
5135
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
5136
+ if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
5137
+ compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE) {
5138
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5139
+ }
4723
5140
  let level = getOptionValue(zipWriter, options, OPTION_LEVEL);
4724
5141
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
4725
5142
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
@@ -4735,7 +5152,7 @@ async function addFile(zipWriter, name, reader, options) {
4735
5152
  if (!useCompressionStream && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
4736
5153
  level = 0;
4737
5154
  }
4738
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5155
+ const zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
4739
5156
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
4740
5157
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
4741
5158
  }
@@ -4746,6 +5163,7 @@ async function addFile(zipWriter, name, reader, options) {
4746
5163
  let offset = 0;
4747
5164
  extraField.forEach(data => extraFieldSize += 4 + getLength(data));
4748
5165
  rawExtraField = new Uint8Array(extraFieldSize);
5166
+ const rawExtraFieldView = getDataView(rawExtraField);
4749
5167
  extraField.forEach((data, type) => {
4750
5168
  if (type > MAX_16_BITS) {
4751
5169
  throw new Error(ERR_INVALID_EXTRAFIELD_TYPE);
@@ -4753,22 +5171,72 @@ async function addFile(zipWriter, name, reader, options) {
4753
5171
  if (getLength(data) > MAX_16_BITS) {
4754
5172
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
4755
5173
  }
4756
- arraySet(rawExtraField, new Uint16Array([type]), offset);
4757
- arraySet(rawExtraField, new Uint16Array([getLength(data)]), offset + 2);
5174
+ setUint16(rawExtraFieldView, offset, type);
5175
+ setUint16(rawExtraFieldView, offset + 2, getLength(data));
4758
5176
  arraySet(rawExtraField, data, offset + 4);
4759
5177
  offset += 4 + getLength(data);
4760
5178
  });
4761
5179
  }
5180
+ return {
5181
+ comment,
5182
+ resolvedOptions: {
5183
+ rawFilename,
5184
+ rawComment,
5185
+ version,
5186
+ lastModDate,
5187
+ lastAccessDate,
5188
+ creationDate,
5189
+ internalFileAttributes,
5190
+ passThrough,
5191
+ password,
5192
+ rawPassword,
5193
+ encryptionStrength,
5194
+ zipCrypto,
5195
+ extendedTimestamp,
5196
+ keepOrder,
5197
+ useWebWorkers,
5198
+ transferStreams,
5199
+ bufferedWrite,
5200
+ createTempStream,
5201
+ dataDescriptorSignature,
5202
+ signal,
5203
+ useUnicodeFileNames,
5204
+ compressionMethod,
5205
+ level,
5206
+ useCompressionStream,
5207
+ dataDescriptor,
5208
+ zip64,
5209
+ rawExtraField
5210
+ }
5211
+ };
5212
+ }
5213
+
5214
+ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
5215
+ const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
5216
+ let { dataDescriptor, zip64, level, compressionMethod } = metadata;
4762
5217
  let maximumCompressedSize = 0;
4763
- let maximumEntrySize = 0;
4764
5218
  let uncompressedSize = 0;
4765
5219
  if (passThrough) {
5220
+ // the headers of a passThrough entry describe the payload verbatim: without a
5221
+ // reader they would declare content that is not there
5222
+ if (!reader) {
5223
+ throw new Error(ERR_UNDEFINED_READER);
5224
+ }
4766
5225
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
4767
5226
  if (uncompressedSize === UNDEFINED_VALUE) {
4768
5227
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
4769
5228
  }
4770
5229
  }
4771
5230
  const zip64Enabled = zip64 === true;
5231
+ const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
5232
+ // entries without a reader have no payload: write them as empty stored files instead of
5233
+ // declaring a compressed or encrypted content that does not exist
5234
+ const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
5235
+ if (!reader) {
5236
+ level = 0;
5237
+ compressionMethod = COMPRESSION_METHOD_STORE;
5238
+ }
5239
+ const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4772
5240
  if (reader) {
4773
5241
  reader = new GenericReader(reader);
4774
5242
  await initStream(reader);
@@ -4781,16 +5249,15 @@ async function addFile(zipWriter, name, reader, options) {
4781
5249
  }
4782
5250
  } else {
4783
5251
  options.uncompressedSize = uncompressedSize = reader.size;
4784
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5252
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4785
5253
  }
4786
5254
  } else {
4787
5255
  options.uncompressedSize = uncompressedSize;
4788
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5256
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4789
5257
  }
4790
5258
  }
4791
- const { diskOffset, diskNumber } = zipWriter.writer;
4792
- const zip64UncompressedSize = zip64Enabled || uncompressedSize > MAX_32_BITS;
4793
- const zip64CompressedSize = zip64Enabled || maximumCompressedSize > MAX_32_BITS;
5259
+ const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
5260
+ const zip64CompressedSize = zip64Enabled || maximumCompressedSize >= MAX_32_BITS;
4794
5261
  if (zip64UncompressedSize || zip64CompressedSize) {
4795
5262
  if (zip64 === false) {
4796
5263
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -4799,73 +5266,19 @@ async function addFile(zipWriter, name, reader, options) {
4799
5266
  }
4800
5267
  }
4801
5268
  zip64 = zip64 || false;
4802
- const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
4803
- options = Object.assign({}, options, {
4804
- rawFilename,
4805
- rawComment,
4806
- version,
4807
- versionMadeBy,
4808
- lastModDate,
4809
- lastAccessDate,
4810
- creationDate,
4811
- rawExtraField,
4812
- zip64,
4813
- zip64UncompressedSize,
4814
- zip64CompressedSize,
4815
- password,
4816
- rawPassword,
4817
- level,
4818
- useWebWorkers,
4819
- transferStreams,
4820
- encryptionStrength,
4821
- extendedTimestamp,
4822
- zipCrypto,
4823
- bufferedWrite,
4824
- createTempStream,
4825
- keepOrder,
4826
- useUnicodeFileNames,
4827
- dataDescriptor,
4828
- dataDescriptorSignature,
4829
- signal,
4830
- msDosCompatible,
4831
- internalFileAttribute: internalFileAttributes,
4832
- internalFileAttributes,
4833
- externalFileAttribute: externalFileAttributes,
4834
- externalFileAttributes,
4835
- useCompressionStream,
4836
- passThrough,
4837
- encrypted: Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted),
4838
- signature: options[PROPERTY_NAME_SIGNATURE],
4839
- compressionMethod,
4840
- uncompressedSize,
4841
- offset: zipWriter.offset - diskOffset,
4842
- diskNumberStart: diskNumber,
4843
- uid,
4844
- gid,
4845
- setuid,
4846
- setgid,
4847
- sticky,
4848
- unixMode,
4849
- msdosAttributesRaw,
4850
- msdosAttributes,
4851
- unixExternalUpper
4852
- });
4853
- const headerInfo = getHeaderInfo(options);
4854
- const dataDescriptorInfo = getDataDescriptorInfo(options);
4855
- const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
4856
- maximumEntrySize = metadataSize + maximumCompressedSize;
4857
- if (zipWriter.options[OPTION_USDZ]) {
4858
- maximumEntrySize += maximumEntrySize + 64;
4859
- }
4860
- zipWriter.pendingEntriesSize += maximumEntrySize;
4861
- let fileEntry;
4862
- try {
4863
- fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
4864
- } finally {
4865
- zipWriter.pendingEntriesSize -= maximumEntrySize;
4866
- }
4867
- Object.assign(fileEntry, { name, comment, extraField });
4868
- return new Entry(fileEntry);
5269
+ return {
5270
+ reader,
5271
+ resolvedOptions: {
5272
+ dataDescriptor,
5273
+ zip64,
5274
+ zip64UncompressedSize,
5275
+ zip64CompressedSize,
5276
+ uncompressedSize,
5277
+ level,
5278
+ compressionMethod,
5279
+ encrypted: encryptedEntry
5280
+ }
5281
+ };
4869
5282
  }
4870
5283
 
4871
5284
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
@@ -4882,37 +5295,40 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4882
5295
  headerInfo
4883
5296
  } = entryInfo;
4884
5297
  const usdz = zipWriter.options[OPTION_USDZ];
4885
- const previousFileEntry = Array.from(files.values()).pop();
5298
+ const previousFileEntry = zipWriter.lastFileEntry;
4886
5299
  let fileEntry = {};
4887
5300
  let bufferedWrite;
4888
5301
  let releaseLockWriter;
4889
5302
  let releaseLockCurrentFileEntry;
4890
5303
  let writingBufferedEntryData;
4891
5304
  let writingEntryData;
5305
+ let writerSizeBeforeEntry;
5306
+ let flushedBufferedSize = 0;
4892
5307
  let fileWriter;
4893
5308
  files.set(name, fileEntry);
5309
+ zipWriter.lastFileEntry = fileEntry;
4894
5310
  try {
4895
5311
  let lockPreviousFileEntry;
4896
5312
  if (keepOrder) {
4897
5313
  lockPreviousFileEntry = previousFileEntry && previousFileEntry.lock;
4898
5314
  requestLockCurrentFileEntry();
4899
5315
  }
4900
- if ((options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) && !usdz) {
5316
+ if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) {
5317
+ bufferedWrite = true;
5318
+ zipWriter.bufferedWrites++;
4901
5319
  if (options.createTempStream) {
4902
5320
  fileWriter = await options.createTempStream();
4903
5321
  } else {
4904
5322
  fileWriter = new TransformStream(UNDEFINED_VALUE, UNDEFINED_VALUE, { highWaterMark: INFINITY_VALUE });
4905
5323
  }
4906
5324
  fileWriter.size = 0;
4907
- bufferedWrite = true;
4908
- zipWriter.bufferedWrites++;
4909
5325
  await initStream(writer);
4910
5326
  } else {
4911
5327
  fileWriter = writer;
4912
5328
  await requestLockWriter();
4913
5329
  }
4914
5330
  await initStream(fileWriter);
4915
- const { writable, diskOffset } = writer;
5331
+ const { diskOffset } = writer;
4916
5332
  if (zipWriter.addSplitZipSignature) {
4917
5333
  delete zipWriter.addSplitZipSignature;
4918
5334
  const signatureArray = new Uint8Array(4);
@@ -4921,21 +5337,20 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4921
5337
  await writeData(writer, signatureArray);
4922
5338
  zipWriter.offset += 4;
4923
5339
  }
4924
- if (usdz) {
5340
+ if (usdz && !bufferedWrite) {
4925
5341
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
4926
5342
  }
4927
- const {
4928
- localHeaderView,
4929
- localHeaderArray
4930
- } = headerInfo;
5343
+ const { localHeaderArray } = headerInfo;
4931
5344
  if (!bufferedWrite) {
4932
5345
  await lockPreviousFileEntry;
4933
- await skipDiskIfNeeded(writable);
5346
+ await skipDiskIfNeeded();
4934
5347
  }
4935
- const { diskNumber } = writer;
4936
- fileEntry.diskNumberStart = diskNumber;
5348
+ const diskNumberStart = writer.diskNumber;
5349
+ const entryOffset = getSegmentOffset(zipWriter, writer);
5350
+ fileEntry.diskNumberStart = diskNumberStart;
4937
5351
  if (!bufferedWrite) {
4938
5352
  writingEntryData = true;
5353
+ writerSizeBeforeEntry = writer.size;
4939
5354
  await writeData(fileWriter, localHeaderArray);
4940
5355
  }
4941
5356
  fileEntry = await createFileEntry(reader, fileWriter, fileEntry, entryInfo, zipWriter.config, options);
@@ -4948,16 +5363,24 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4948
5363
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
4949
5364
  await requestLockWriter();
4950
5365
  writingBufferedEntryData = true;
5366
+ writerSizeBeforeEntry = writer.size;
5367
+ await skipDiskIfNeeded();
4951
5368
  fileEntry.diskNumberStart = writer.diskNumber;
4952
- fileEntry.offset = zipWriter.offset - writer.diskOffset;
4953
- updateLocalHeader(fileEntry, localHeaderView, options);
4954
- await skipDiskIfNeeded(writable);
4955
- await writeData(writer, localHeaderArray);
4956
- await fileWriter.readable.pipeTo(writable, { preventClose: true, preventAbort: true, signal });
5369
+ fileEntry.offset = getSegmentOffset(zipWriter, writer);
5370
+ if (usdz) {
5371
+ // the padding depends on the entry offset, only known now that the writer is locked
5372
+ const previousMetadataSize = entryInfo.metadataSize;
5373
+ appendExtraFieldUSDZ(entryInfo, zipWriter.offset - writer.diskOffset);
5374
+ fileEntry.size += entryInfo.metadataSize - previousMetadataSize;
5375
+ }
5376
+ updateLocalHeader(fileEntry, headerInfo.localHeaderView, options);
5377
+ await writeData(writer, headerInfo.localHeaderArray);
5378
+ await flushBufferedData(fileWriter.readable, writer, signal, chunkLength => flushedBufferedSize += chunkLength);
4957
5379
  writer.size += fileWriter.size;
4958
5380
  writingBufferedEntryData = false;
4959
5381
  } else {
4960
- fileEntry.offset = zipWriter.offset - diskOffset;
5382
+ fileEntry.diskNumberStart = diskNumberStart;
5383
+ fileEntry.offset = entryOffset;
4961
5384
  }
4962
5385
  zipWriter.offset += fileEntry.size;
4963
5386
  return fileEntry;
@@ -4971,10 +5394,9 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4971
5394
  // ignored
4972
5395
  }
4973
5396
  }
5397
+ zipWriter.offset += writer.size - writerSizeBeforeEntry;
4974
5398
  if (bufferedWrite) {
4975
- zipWriter.offset += fileWriter.size;
4976
- } else {
4977
- zipWriter.offset = fileWriter.size;
5399
+ zipWriter.offset += flushedBufferedSize;
4978
5400
  }
4979
5401
  }
4980
5402
  files.delete(name);
@@ -5005,10 +5427,10 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
5005
5427
  await lockWriter;
5006
5428
  }
5007
5429
 
5008
- async function skipDiskIfNeeded(writable) {
5430
+ async function skipDiskIfNeeded() {
5009
5431
  if (getLength(headerInfo.localHeaderArray) > writer.availableSize) {
5010
5432
  writer.availableSize = 0;
5011
- await writeData(writable, new Uint8Array());
5433
+ await writeData(writer, new Uint8Array());
5012
5434
  }
5013
5435
  }
5014
5436
  }
@@ -5149,6 +5571,10 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
5149
5571
  uncompressedSize = result.inputSize;
5150
5572
  signature = result.signature;
5151
5573
  }
5574
+ if ((!zip64CompressedSize && compressedSize >= MAX_32_BITS) ||
5575
+ (!zip64UncompressedSize && uncompressedSize >= MAX_32_BITS)) {
5576
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
5577
+ }
5152
5578
  } catch (error) {
5153
5579
  if (error.outputSize !== UNDEFINED_VALUE) {
5154
5580
  writer.size += error.outputSize;
@@ -5211,35 +5637,28 @@ function getHeaderInfo(options) {
5211
5637
  uncompressedSize
5212
5638
  } = options;
5213
5639
  let { version, compressionMethod } = options;
5214
- const compressed = !directory && (level > 0 || (level === UNDEFINED_VALUE && compressionMethod !== 0));
5640
+ const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
5641
+ ? (level === UNDEFINED_VALUE || level > 0)
5642
+ : compressionMethod !== COMPRESSION_METHOD_STORE);
5215
5643
  let rawLocalExtraFieldZip64;
5216
5644
  const uncompressedFile = passThrough || !compressed;
5217
- const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5218
- if (zip64) {
5219
- let rawLocalExtraFieldZip64Length = 4;
5220
- if (zip64UncompressedSize) {
5221
- rawLocalExtraFieldZip64Length += 8;
5222
- }
5223
- if (zip64CompressedSize) {
5224
- rawLocalExtraFieldZip64Length += 8;
5225
- }
5226
- rawLocalExtraFieldZip64 = new Uint8Array(rawLocalExtraFieldZip64Length);
5227
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5228
- setUint16(rawLocalExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5229
- setUint16(rawLocalExtraFieldZip64View, 2, getLength(rawLocalExtraFieldZip64) - 4);
5645
+ // entries without a data descriptor are always buffered (cf. getFileEntry), so the
5646
+ // zip64 extra field values can be patched into the local header before flushing it
5647
+ const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5648
+ const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
5649
+ if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
5650
+ // APPNOTE 4.5.3: the zip64 extra field of a local header must include both the
5651
+ // uncompressed and compressed size fields
5652
+ const length = 4 + 16;
5653
+ const extraFieldZip64 = createRecordWriter(length);
5654
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
5655
+ extraFieldZip64.uint16(length - 4);
5656
+ rawLocalExtraFieldZip64 = extraFieldZip64.array;
5230
5657
  if (zip64ExtraFieldComplete) {
5231
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5232
- let rawLocalExtraFieldZip64Offset = 4;
5233
- if (zip64UncompressedSize) {
5234
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5235
- rawLocalExtraFieldZip64Offset += 8;
5236
- }
5237
- if (zip64CompressedSize && uncompressedFile) {
5238
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5239
- rawLocalExtraFieldZip64Offset += 8;
5240
- }
5241
- if (rawLocalExtraFieldZip64Offset == 4) {
5242
- rawLocalExtraFieldZip64 = new Uint8Array();
5658
+ extraFieldZip64.uint64(uncompressedSize);
5659
+ if (uncompressedFile) {
5660
+ const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
5661
+ extraFieldZip64.uint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
5243
5662
  }
5244
5663
  }
5245
5664
  } else {
@@ -5247,11 +5666,11 @@ function getHeaderInfo(options) {
5247
5666
  }
5248
5667
  let rawExtraFieldAES;
5249
5668
  if (encrypted && !zipCrypto) {
5250
- rawExtraFieldAES = new Uint8Array(getLength(EXTRAFIELD_DATA_AES) + 2);
5251
- const extraFieldAESView = getDataView(rawExtraFieldAES);
5252
- setUint16(extraFieldAESView, 0, EXTRAFIELD_TYPE_AES);
5253
- arraySet(rawExtraFieldAES, EXTRAFIELD_DATA_AES, 2);
5254
- setUint8(extraFieldAESView, 8, encryptionStrength);
5669
+ const extraFieldAES = createRecordWriter(getLength(EXTRAFIELD_DATA_AES) + 2);
5670
+ extraFieldAES.uint16(EXTRAFIELD_TYPE_AES);
5671
+ extraFieldAES.bytes(EXTRAFIELD_DATA_AES);
5672
+ rawExtraFieldAES = extraFieldAES.array;
5673
+ rawExtraFieldAES[8] = encryptionStrength;
5255
5674
  } else {
5256
5675
  rawExtraFieldAES = new Uint8Array();
5257
5676
  }
@@ -5259,33 +5678,38 @@ function getHeaderInfo(options) {
5259
5678
  let rawExtraFieldExtendedTimestamp;
5260
5679
  let extraFieldExtendedTimestampFlag;
5261
5680
  if (extendedTimestamp) {
5262
- rawExtraFieldExtendedTimestamp = new Uint8Array(9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0));
5263
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldExtendedTimestamp);
5264
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5265
- setUint16(extraFieldExtendedTimestampView, 2, getLength(rawExtraFieldExtendedTimestamp) - 4);
5266
- extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5267
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5268
- let offset = 5;
5269
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastModDate.getTime() / 1000));
5270
- offset += 4;
5271
- if (lastAccessDate) {
5272
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastAccessDate.getTime() / 1000));
5273
- offset += 4;
5274
- }
5275
- if (creationDate) {
5276
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(creationDate.getTime() / 1000));
5681
+ const lastModTimeUnix = getTimeUnix(lastModDate);
5682
+ if (inUnixTimeRange(lastModTimeUnix)) {
5683
+ const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
5684
+ const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
5685
+ extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5686
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5687
+ extraFieldTimestamp.uint16(extraFieldTimestampLength - 4);
5688
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
5689
+ extraFieldTimestamp.uint32(lastModTimeUnix);
5690
+ if (lastAccessDate) {
5691
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(lastAccessDate)));
5692
+ }
5693
+ if (creationDate) {
5694
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(creationDate)));
5695
+ }
5696
+ rawExtraFieldExtendedTimestamp = extraFieldTimestamp.array;
5697
+ } else {
5698
+ // the date cannot be stored as a 32-bit time_t; the NTFS field replaces it
5699
+ rawExtraFieldExtendedTimestamp = new Uint8Array();
5277
5700
  }
5278
5701
  try {
5279
- rawExtraFieldNTFS = new Uint8Array(36);
5280
- const extraFieldNTFSView = getDataView(rawExtraFieldNTFS);
5281
5702
  const lastModTimeNTFS = getTimeNTFS(lastModDate);
5282
- setUint16(extraFieldNTFSView, 0, EXTRAFIELD_TYPE_NTFS);
5283
- setUint16(extraFieldNTFSView, 2, 32);
5284
- setUint16(extraFieldNTFSView, 8, EXTRAFIELD_TYPE_NTFS_TAG1);
5285
- setUint16(extraFieldNTFSView, 10, 24);
5286
- setBigUint64(extraFieldNTFSView, 12, lastModTimeNTFS);
5287
- setBigUint64(extraFieldNTFSView, 20, getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5288
- setBigUint64(extraFieldNTFSView, 28, getTimeNTFS(creationDate) || lastModTimeNTFS);
5703
+ const extraFieldNTFS = createRecordWriter(36);
5704
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
5705
+ extraFieldNTFS.uint16(32);
5706
+ extraFieldNTFS.skip(4);
5707
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
5708
+ extraFieldNTFS.uint16(24);
5709
+ extraFieldNTFS.uint64(lastModTimeNTFS);
5710
+ extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5711
+ extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
5712
+ rawExtraFieldNTFS = extraFieldNTFS.array;
5289
5713
  } catch {
5290
5714
  rawExtraFieldNTFS = new Uint8Array();
5291
5715
  }
@@ -5294,41 +5718,27 @@ function getHeaderInfo(options) {
5294
5718
  }
5295
5719
  let rawExtraFieldUnix;
5296
5720
  try {
5297
- const { uid, gid, unixMode, setuid, setgid, sticky, unixExtraFieldType } = options;
5298
- if (unixExtraFieldType && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE)) {
5721
+ const { uid, gid, unixExtraFieldType } = options;
5722
+ if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5299
5723
  const uidBytes = packUnixId(uid);
5300
5724
  const gidBytes = packUnixId(gid);
5301
- let modeArray = new Uint8Array();
5302
- if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && unixMode !== UNDEFINED_VALUE) {
5303
- let modeToWrite = unixMode & MAX_16_BITS;
5304
- if (setuid) {
5305
- modeToWrite |= FILE_ATTR_UNIX_SETUID_MASK;
5306
- }
5307
- if (setgid) {
5308
- modeToWrite |= FILE_ATTR_UNIX_SETGID_MASK;
5309
- }
5310
- if (sticky) {
5311
- modeToWrite |= FILE_ATTR_UNIX_STICKY_MASK;
5312
- }
5313
- modeArray = new Uint8Array(2);
5314
- const modeDataView = new DataView(modeArray.buffer);
5315
- modeDataView.setUint16(0, modeToWrite, true);
5316
- }
5317
- const payloadLength = 3 + uidBytes.length + gidBytes.length + modeArray.length;
5318
- rawExtraFieldUnix = new Uint8Array(4 + payloadLength);
5319
- const rawExtraFieldUnixView = getDataView(rawExtraFieldUnix);
5320
- setUint16(rawExtraFieldUnixView, 0, unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE ? EXTRAFIELD_TYPE_INFOZIP : EXTRAFIELD_TYPE_UNIX);
5321
- setUint16(rawExtraFieldUnixView, 2, payloadLength);
5322
- setUint8(rawExtraFieldUnixView, 4, 1);
5323
- setUint8(rawExtraFieldUnixView, 5, uidBytes.length);
5324
- let offset = 6;
5325
- arraySet(rawExtraFieldUnix, uidBytes, offset);
5326
- offset += uidBytes.length;
5327
- setUint8(rawExtraFieldUnixView, offset, gidBytes.length);
5328
- offset++;
5329
- arraySet(rawExtraFieldUnix, gidBytes, offset);
5330
- offset += gidBytes.length;
5331
- arraySet(rawExtraFieldUnix, modeArray, offset);
5725
+ const payloadLength = 3 + uidBytes.length + gidBytes.length;
5726
+ const extraFieldUnix = createRecordWriter(4 + payloadLength);
5727
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_INFOZIP);
5728
+ extraFieldUnix.uint16(payloadLength);
5729
+ extraFieldUnix.uint8(1);
5730
+ extraFieldUnix.uint8(uidBytes.length);
5731
+ extraFieldUnix.bytes(uidBytes);
5732
+ extraFieldUnix.uint8(gidBytes.length);
5733
+ extraFieldUnix.bytes(gidBytes);
5734
+ rawExtraFieldUnix = extraFieldUnix.array;
5735
+ } else if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5736
+ const extraFieldUnix = createRecordWriter(8);
5737
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_UNIX);
5738
+ extraFieldUnix.uint16(4);
5739
+ extraFieldUnix.uint16((uid === UNDEFINED_VALUE ? 0 : uid) & MAX_16_BITS);
5740
+ extraFieldUnix.uint16((gid === UNDEFINED_VALUE ? 0 : gid) & MAX_16_BITS);
5741
+ rawExtraFieldUnix = extraFieldUnix.array;
5332
5742
  } else {
5333
5743
  rawExtraFieldUnix = new Uint8Array();
5334
5744
  }
@@ -5346,8 +5756,11 @@ function getHeaderInfo(options) {
5346
5756
  rawExtraFieldAES[9] = compressionMethod;
5347
5757
  compressionMethod = COMPRESSION_METHOD_AES;
5348
5758
  }
5349
- const localExtraFieldZip64Length = zip64ExtraFieldComplete ? getLength(rawLocalExtraFieldZip64) : 0;
5759
+ const localExtraFieldZip64Length = writeLocalExtraFieldZip64 ? getLength(rawLocalExtraFieldZip64) : 0;
5350
5760
  const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5761
+ if (extraFieldLength > MAX_16_BITS) {
5762
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
5763
+ }
5351
5764
  const {
5352
5765
  headerArray,
5353
5766
  headerView,
@@ -5363,29 +5776,27 @@ function getHeaderInfo(options) {
5363
5776
  zip64UncompressedSize,
5364
5777
  extraFieldLength
5365
5778
  });
5366
- let localHeaderOffset = HEADER_SIZE;
5367
- const localHeaderArray = new Uint8Array(localHeaderOffset + getLength(rawFilename) + extraFieldLength);
5779
+ const localHeader = createRecordWriter(HEADER_SIZE + getLength(rawFilename) + extraFieldLength);
5780
+ const localHeaderArray = localHeader.array;
5368
5781
  const localHeaderView = getDataView(localHeaderArray);
5369
- setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE);
5370
- arraySet(localHeaderArray, headerArray, 4);
5371
- arraySet(localHeaderArray, rawFilename, localHeaderOffset);
5372
- localHeaderOffset += getLength(rawFilename);
5373
- if (zip64ExtraFieldComplete) {
5374
- arraySet(localHeaderArray, rawLocalExtraFieldZip64, localHeaderOffset);
5375
- }
5376
- localHeaderOffset += localExtraFieldZip64Length;
5377
- arraySet(localHeaderArray, rawExtraFieldAES, localHeaderOffset);
5378
- localHeaderOffset += getLength(rawExtraFieldAES);
5379
- arraySet(localHeaderArray, rawExtraFieldExtendedTimestamp, localHeaderOffset);
5380
- localHeaderOffset += getLength(rawExtraFieldExtendedTimestamp);
5381
- arraySet(localHeaderArray, rawExtraFieldNTFS, localHeaderOffset);
5382
- localHeaderOffset += getLength(rawExtraFieldNTFS);
5383
- arraySet(localHeaderArray, rawExtraFieldUnix, localHeaderOffset);
5384
- localHeaderOffset += getLength(rawExtraFieldUnix);
5385
- arraySet(localHeaderArray, rawExtraField, localHeaderOffset);
5782
+ localHeader.uint32(LOCAL_FILE_HEADER_SIGNATURE);
5783
+ localHeader.bytes(headerArray);
5784
+ localHeader.bytes(rawFilename);
5785
+ if (writeLocalExtraFieldZip64) {
5786
+ localHeader.bytes(rawLocalExtraFieldZip64);
5787
+ }
5788
+ localHeader.bytes(rawExtraFieldAES);
5789
+ localHeader.bytes(rawExtraFieldExtendedTimestamp);
5790
+ localHeader.bytes(rawExtraFieldNTFS);
5791
+ localHeader.bytes(rawExtraFieldUnix);
5792
+ localHeader.bytes(rawExtraField);
5386
5793
  if (dataDescriptor) {
5387
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, 0);
5388
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, 0);
5794
+ if (!zip64CompressedSize) {
5795
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5796
+ }
5797
+ if (!zip64UncompressedSize) {
5798
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5799
+ }
5389
5800
  }
5390
5801
  return {
5391
5802
  localHeaderArray,
@@ -5412,7 +5823,7 @@ function getHeaderInfo(options) {
5412
5823
  function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
5413
5824
  const { headerInfo } = entryInfo;
5414
5825
  let { localHeaderArray, extraFieldLength } = headerInfo;
5415
- let localHeaderArrayView = getDataView(localHeaderArray);
5826
+ let localHeaderArrayView;
5416
5827
  let extraBytesLength = 64 - ((zipWriterOffset + getLength(localHeaderArray)) % 64);
5417
5828
  if (extraBytesLength < 4) {
5418
5829
  extraBytesLength += 64;
@@ -5420,13 +5831,14 @@ function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
5420
5831
  const rawExtraFieldUSDZ = new Uint8Array(extraBytesLength);
5421
5832
  const extraFieldUSDZView = getDataView(rawExtraFieldUSDZ);
5422
5833
  setUint16(extraFieldUSDZView, 0, EXTRAFIELD_TYPE_USDZ);
5423
- setUint16(extraFieldUSDZView, 2, extraBytesLength - 2);
5834
+ setUint16(extraFieldUSDZView, 2, extraBytesLength - 4);
5424
5835
  const previousLocalHeaderArray = localHeaderArray;
5425
5836
  headerInfo.localHeaderArray = localHeaderArray = new Uint8Array(getLength(previousLocalHeaderArray) + extraBytesLength);
5426
5837
  arraySet(localHeaderArray, previousLocalHeaderArray);
5427
5838
  arraySet(localHeaderArray, rawExtraFieldUSDZ, getLength(previousLocalHeaderArray));
5428
5839
  localHeaderArrayView = getDataView(localHeaderArray);
5429
5840
  setUint16(localHeaderArrayView, 28, extraFieldLength + extraBytesLength);
5841
+ headerInfo.localHeaderView = localHeaderArrayView;
5430
5842
  entryInfo.metadataSize += extraBytesLength;
5431
5843
  }
5432
5844
 
@@ -5549,37 +5961,32 @@ function updateLocalHeader({
5549
5961
  }, localHeaderView, { dataDescriptor }) {
5550
5962
  if (!dataDescriptor) {
5551
5963
  if (!encrypted) {
5552
- setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + 4, signature);
5964
+ setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, signature);
5553
5965
  }
5554
5966
  if (!zip64CompressedSize) {
5555
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, compressedSize);
5967
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, compressedSize);
5556
5968
  }
5557
5969
  if (!zip64UncompressedSize) {
5558
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, uncompressedSize);
5970
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, uncompressedSize);
5559
5971
  }
5560
5972
  }
5561
5973
  if (zip64 && localExtraFieldZip64Length) {
5562
- let localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
5563
- if (zip64UncompressedSize) {
5564
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
5565
- localHeaderOffset += 8;
5566
- }
5567
- if (zip64CompressedSize) {
5568
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(compressedSize));
5569
- localHeaderOffset += 8;
5570
- }
5974
+ // the local zip64 extra field always contains both size slots
5975
+ const localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
5976
+ setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
5977
+ setBigUint64(localHeaderView, localHeaderOffset + 8, BigInt(compressedSize));
5571
5978
  }
5572
5979
  }
5573
5980
 
5574
5981
 
5575
5982
  async function closeFile(zipWriter, comment, options) {
5576
- const { files, writer } = zipWriter;
5577
- const { diskOffset } = writer;
5578
- let { diskNumber } = writer;
5579
- let offset = 0;
5983
+ const directoryDataLength = createDirectoryRecords(zipWriter.files);
5984
+ const { cdStartDiskNumber, cdStartDiskOffset } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
5985
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { cdStartDiskNumber, cdStartDiskOffset, directoryDataLength });
5986
+ }
5987
+
5988
+ function createDirectoryRecords(files) {
5580
5989
  let directoryDataLength = 0;
5581
- let directoryOffset = zipWriter.offset - diskOffset;
5582
- let filesLength = files.size;
5583
5990
  for (const [, fileEntry] of files) {
5584
5991
  const {
5585
5992
  rawFilename,
@@ -5596,24 +6003,27 @@ async function closeFile(zipWriter, comment, options) {
5596
6003
  uncompressedSize,
5597
6004
  compressedSize
5598
6005
  } = fileEntry;
5599
- const zip64Offset = fileEntry.offset > MAX_32_BITS;
5600
- const zip64DiskNumberStart = fileEntry.diskNumberStart > MAX_16_BITS;
6006
+ const zip64Offset = fileEntry.offset >= MAX_32_BITS;
6007
+ const zip64DiskNumberStart = fileEntry.diskNumberStart >= MAX_16_BITS;
5601
6008
  let rawExtraFieldZip64;
5602
6009
  if (zip64Offset || zip64DiskNumberStart || zip64UncompressedSize || zip64CompressedSize) {
5603
- let length = 4;
5604
- if (zip64UncompressedSize) length += 8;
5605
- if (zip64CompressedSize) length += 8;
5606
- if (zip64Offset) length += 8;
5607
- if (zip64DiskNumberStart) length += 4;
5608
- rawExtraFieldZip64 = new Uint8Array(length);
5609
- const zip64View = getDataView(rawExtraFieldZip64);
5610
- setUint16(zip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5611
- setUint16(zip64View, 2, length - 4);
5612
- let zip64FieldOffset = 4;
5613
- if (zip64UncompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(uncompressedSize)); zip64FieldOffset += 8; }
5614
- if (zip64CompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(compressedSize)); zip64FieldOffset += 8; }
5615
- if (zip64Offset) { setBigUint64(zip64View, zip64FieldOffset, BigInt(fileEntry.offset)); zip64FieldOffset += 8; }
5616
- if (zip64DiskNumberStart) { setUint32(zip64View, zip64FieldOffset, fileEntry.diskNumberStart); }
6010
+ const length = 4 + (zip64UncompressedSize ? 8 : 0) + (zip64CompressedSize ? 8 : 0) + (zip64Offset ? 8 : 0) + (zip64DiskNumberStart ? 4 : 0);
6011
+ const extraFieldZip64 = createRecordWriter(length);
6012
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
6013
+ extraFieldZip64.uint16(length - 4);
6014
+ if (zip64UncompressedSize) {
6015
+ extraFieldZip64.uint64(uncompressedSize);
6016
+ }
6017
+ if (zip64CompressedSize) {
6018
+ extraFieldZip64.uint64(compressedSize);
6019
+ }
6020
+ if (zip64Offset) {
6021
+ extraFieldZip64.uint64(fileEntry.offset);
6022
+ }
6023
+ if (zip64DiskNumberStart) {
6024
+ extraFieldZip64.uint32(fileEntry.diskNumberStart);
6025
+ }
6026
+ rawExtraFieldZip64 = extraFieldZip64.array;
5617
6027
  } else {
5618
6028
  rawExtraFieldZip64 = new Uint8Array();
5619
6029
  }
@@ -5621,32 +6031,41 @@ async function closeFile(zipWriter, comment, options) {
5621
6031
  fileEntry.zip64Offset = zip64Offset;
5622
6032
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
5623
6033
  let rawExtraFieldTimestamp;
5624
- if (extendedTimestamp) {
5625
- rawExtraFieldTimestamp = new Uint8Array(9);
5626
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldTimestamp);
5627
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5628
- setUint16(extraFieldExtendedTimestampView, 2, 5);
5629
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5630
- setUint32(extraFieldExtendedTimestampView, 5, Math.floor(lastModDate.getTime() / 1000));
6034
+ const lastModTimeUnix = getTimeUnix(lastModDate);
6035
+ if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
6036
+ const extraFieldTimestamp = createRecordWriter(9);
6037
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
6038
+ extraFieldTimestamp.uint16(5);
6039
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
6040
+ extraFieldTimestamp.uint32(lastModTimeUnix);
6041
+ rawExtraFieldTimestamp = extraFieldTimestamp.array;
5631
6042
  } else {
5632
6043
  rawExtraFieldTimestamp = new Uint8Array();
5633
6044
  }
5634
6045
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
5635
- directoryDataLength += 46 +
5636
- getLength(
5637
- rawFilename,
5638
- rawComment,
5639
- rawExtraFieldZip64,
5640
- rawExtraFieldAES,
5641
- rawExtraFieldNTFS,
5642
- rawExtraFieldUnix,
5643
- rawExtraFieldTimestamp,
5644
- rawExtraField);
6046
+ const extraFieldLength = getLength(
6047
+ rawExtraFieldZip64,
6048
+ rawExtraFieldAES,
6049
+ rawExtraFieldNTFS,
6050
+ rawExtraFieldUnix,
6051
+ rawExtraFieldTimestamp,
6052
+ rawExtraField);
6053
+ if (extraFieldLength > MAX_16_BITS) {
6054
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
6055
+ }
6056
+ directoryDataLength += CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
5645
6057
  }
6058
+ return directoryDataLength;
6059
+ }
6060
+
6061
+ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
6062
+ const { files, writer } = zipWriter;
5646
6063
  const directoryArray = new Uint8Array(directoryDataLength);
5647
- const directoryView = getDataView(directoryArray);
5648
6064
  await initStream(writer);
6065
+ let offset = 0;
5649
6066
  let directoryDiskOffset = 0;
6067
+ let cdStartDiskNumber = writer.diskNumber;
6068
+ let cdStartDiskOffset = writer.diskOffset;
5650
6069
  for (const [indexFileEntry, fileEntry] of Array.from(files.values()).entries()) {
5651
6070
  const {
5652
6071
  offset: fileEntryOffset,
@@ -5672,52 +6091,46 @@ async function closeFile(zipWriter, comment, options) {
5672
6091
  compressedSize
5673
6092
  } = fileEntry;
5674
6093
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5675
- setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE);
5676
- setUint16(directoryView, offset + 4, versionMadeBy);
6094
+ const directoryRecordLength = CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
6095
+ if (offset + directoryRecordLength - directoryDiskOffset > writer.availableSize) {
6096
+ await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
6097
+ directoryDiskOffset = offset;
6098
+ writer.availableSize = 0;
6099
+ await writeData(writer, new Uint8Array());
6100
+ }
6101
+ if (indexFileEntry == 0) {
6102
+ cdStartDiskNumber = writer.diskNumber;
6103
+ cdStartDiskOffset = writer.diskOffset;
6104
+ }
5677
6105
  if (!zip64UncompressedSize) {
5678
6106
  setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, uncompressedSize);
5679
6107
  }
5680
6108
  if (!zip64CompressedSize) {
5681
6109
  setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, compressedSize);
5682
6110
  }
5683
- arraySet(directoryArray, headerArray, offset + 6);
5684
- let directoryOffset = offset + HEADER_SIZE;
5685
- setUint16(directoryView, directoryOffset, extraFieldLength);
5686
- directoryOffset += 2;
5687
- setUint16(directoryView, directoryOffset, getLength(rawComment));
5688
- directoryOffset += 2;
5689
- setUint16(directoryView, directoryOffset, zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
5690
- directoryOffset += 2;
5691
- setUint16(directoryView, directoryOffset, internalFileAttributes);
5692
- directoryOffset += 2;
5693
- if (externalFileAttributes) {
5694
- setUint32(directoryView, directoryOffset, externalFileAttributes);
5695
- }
5696
- directoryOffset += 4;
5697
- setUint32(directoryView, directoryOffset, zip64Offset ? MAX_32_BITS : fileEntryOffset);
5698
- directoryOffset += 4;
5699
- arraySet(directoryArray, rawFilename, directoryOffset);
5700
- directoryOffset += getLength(rawFilename);
5701
- arraySet(directoryArray, rawExtraFieldZip64, directoryOffset);
5702
- directoryOffset += getLength(rawExtraFieldZip64);
5703
- arraySet(directoryArray, rawExtraFieldAES, directoryOffset);
5704
- directoryOffset += getLength(rawExtraFieldAES);
5705
- arraySet(directoryArray, rawExtraFieldExtendedTimestamp, directoryOffset);
5706
- directoryOffset += getLength(rawExtraFieldExtendedTimestamp);
5707
- arraySet(directoryArray, rawExtraFieldNTFS, directoryOffset);
5708
- directoryOffset += getLength(rawExtraFieldNTFS);
5709
- arraySet(directoryArray, rawExtraFieldUnix, directoryOffset);
5710
- directoryOffset += getLength(rawExtraFieldUnix);
5711
- arraySet(directoryArray, rawExtraField, directoryOffset);
5712
- directoryOffset += getLength(rawExtraField);
5713
- arraySet(directoryArray, rawComment, directoryOffset);
5714
- directoryOffset += getLength(rawComment);
5715
- if (offset - directoryDiskOffset > writer.availableSize) {
5716
- writer.availableSize = 0;
5717
- await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
5718
- directoryDiskOffset = offset;
5719
- }
5720
- offset = directoryOffset;
6111
+ if ((zip64Offset || zip64DiskNumberStart) && fileEntry.version < VERSION_ZIP64) {
6112
+ setUint16(headerView, HEADER_OFFSET_VERSION, VERSION_ZIP64);
6113
+ }
6114
+ const directoryRecord = createRecordWriter(directoryRecordLength);
6115
+ directoryRecord.uint32(CENTRAL_FILE_HEADER_SIGNATURE);
6116
+ directoryRecord.uint16(versionMadeBy);
6117
+ directoryRecord.bytes(headerArray.subarray(0, HEADER_SIZE - 4 - 2));
6118
+ directoryRecord.uint16(extraFieldLength);
6119
+ directoryRecord.uint16(getLength(rawComment));
6120
+ directoryRecord.uint16(zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
6121
+ directoryRecord.uint16(internalFileAttributes);
6122
+ directoryRecord.uint32(externalFileAttributes);
6123
+ directoryRecord.uint32(zip64Offset ? MAX_32_BITS : fileEntryOffset);
6124
+ directoryRecord.bytes(rawFilename);
6125
+ directoryRecord.bytes(rawExtraFieldZip64);
6126
+ directoryRecord.bytes(rawExtraFieldAES);
6127
+ directoryRecord.bytes(rawExtraFieldExtendedTimestamp);
6128
+ directoryRecord.bytes(rawExtraFieldNTFS);
6129
+ directoryRecord.bytes(rawExtraFieldUnix);
6130
+ directoryRecord.bytes(rawExtraField);
6131
+ directoryRecord.bytes(rawComment);
6132
+ arraySet(directoryArray, directoryRecord.array, offset);
6133
+ offset += directoryRecordLength;
5721
6134
  if (options.onprogress) {
5722
6135
  try {
5723
6136
  await options.onprogress(indexFileEntry + 1, files.size, new Entry(fileEntry));
@@ -5727,36 +6140,53 @@ async function closeFile(zipWriter, comment, options) {
5727
6140
  }
5728
6141
  }
5729
6142
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
6143
+ return { cdStartDiskNumber, cdStartDiskOffset };
6144
+ }
6145
+
6146
+ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
6147
+ const { writer } = zipWriter;
6148
+ const { cdStartDiskNumber, cdStartDiskOffset } = cdInfo;
6149
+ let { directoryDataLength } = cdInfo;
6150
+ let filesLength = zipWriter.files.size;
6151
+ let diskNumber = cdStartDiskNumber;
6152
+ let directoryOffset = zipWriter.offset - cdStartDiskOffset - (cdStartDiskNumber ? zipWriter.initialOffset : 0);
5730
6153
  let lastDiskNumber = writer.diskNumber;
5731
- const { availableSize } = writer;
5732
- if (availableSize < END_OF_CENTRAL_DIR_LENGTH) {
6154
+ if (writer.availableSize < END_OF_CENTRAL_DIR_LENGTH) {
5733
6155
  lastDiskNumber++;
5734
6156
  }
5735
6157
  let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5736
- if (directoryOffset > MAX_32_BITS || directoryDataLength > MAX_32_BITS || filesLength > MAX_16_BITS || lastDiskNumber > MAX_16_BITS) {
6158
+ if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || filesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
5737
6159
  if (zip64 === false) {
5738
6160
  throw new Error(ERR_UNSUPPORTED_FORMAT);
5739
6161
  } else {
5740
6162
  zip64 = true;
5741
6163
  }
5742
6164
  }
5743
- const endOfdirectoryArray = new Uint8Array(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
5744
- const endOfdirectoryView = getDataView(endOfdirectoryArray);
5745
- offset = 0;
6165
+ const commentLength = getLength(comment);
6166
+ if (commentLength > MAX_16_BITS) {
6167
+ throw new Error(ERR_INVALID_COMMENT);
6168
+ }
6169
+ const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6170
+ if (getLength(endOfdirectoryRecord.array) + commentLength > writer.availableSize) {
6171
+ writer.availableSize = 0;
6172
+ await writeData(writer, new Uint8Array());
6173
+ }
6174
+ lastDiskNumber = writer.diskNumber;
5746
6175
  if (zip64) {
5747
- setUint32(endOfdirectoryView, 0, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
5748
- setBigUint64(endOfdirectoryView, 4, BigInt(44));
5749
- setUint16(endOfdirectoryView, 12, 45);
5750
- setUint16(endOfdirectoryView, 14, 45);
5751
- setUint32(endOfdirectoryView, 16, lastDiskNumber);
5752
- setUint32(endOfdirectoryView, 20, diskNumber);
5753
- setBigUint64(endOfdirectoryView, 24, BigInt(filesLength));
5754
- setBigUint64(endOfdirectoryView, 32, BigInt(filesLength));
5755
- setBigUint64(endOfdirectoryView, 40, BigInt(directoryDataLength));
5756
- setBigUint64(endOfdirectoryView, 48, BigInt(directoryOffset));
5757
- setUint32(endOfdirectoryView, 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
5758
- setBigUint64(endOfdirectoryView, 64, BigInt(directoryOffset) + BigInt(directoryDataLength));
5759
- setUint32(endOfdirectoryView, 72, lastDiskNumber + 1);
6176
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
6177
+ endOfdirectoryRecord.uint64(44);
6178
+ endOfdirectoryRecord.uint16(45);
6179
+ endOfdirectoryRecord.uint16(45);
6180
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6181
+ endOfdirectoryRecord.uint32(diskNumber);
6182
+ endOfdirectoryRecord.uint64(filesLength);
6183
+ endOfdirectoryRecord.uint64(filesLength);
6184
+ endOfdirectoryRecord.uint64(directoryDataLength);
6185
+ endOfdirectoryRecord.uint64(directoryOffset);
6186
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
6187
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6188
+ endOfdirectoryRecord.uint64(BigInt(zipWriter.offset) + BigInt(directoryDataLength) - BigInt(writer.diskOffset) - BigInt(writer.diskNumber ? zipWriter.initialOffset : 0));
6189
+ endOfdirectoryRecord.uint32(lastDiskNumber + 1);
5760
6190
  const supportZip64SplitFile = getOptionValue(zipWriter, options, OPTION_SUPPORT_ZIP64_SPLIT_FILE, true);
5761
6191
  if (supportZip64SplitFile) {
5762
6192
  lastDiskNumber = MAX_16_BITS;
@@ -5765,29 +6195,40 @@ async function closeFile(zipWriter, comment, options) {
5765
6195
  filesLength = MAX_16_BITS;
5766
6196
  directoryOffset = MAX_32_BITS;
5767
6197
  directoryDataLength = MAX_32_BITS;
5768
- offset += ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
5769
- }
5770
- setUint32(endOfdirectoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE);
5771
- setUint16(endOfdirectoryView, offset + 4, lastDiskNumber);
5772
- setUint16(endOfdirectoryView, offset + 6, diskNumber);
5773
- setUint16(endOfdirectoryView, offset + 8, filesLength);
5774
- setUint16(endOfdirectoryView, offset + 10, filesLength);
5775
- setUint32(endOfdirectoryView, offset + 12, directoryDataLength);
5776
- setUint32(endOfdirectoryView, offset + 16, directoryOffset);
5777
- const commentLength = getLength(comment);
5778
- if (commentLength) {
5779
- if (commentLength <= MAX_16_BITS) {
5780
- setUint16(endOfdirectoryView, offset + 20, commentLength);
5781
- } else {
5782
- throw new Error(ERR_INVALID_COMMENT);
5783
- }
5784
6198
  }
5785
- await writeData(writer, endOfdirectoryArray);
6199
+ endOfdirectoryRecord.uint32(END_OF_CENTRAL_DIR_SIGNATURE);
6200
+ endOfdirectoryRecord.uint16(lastDiskNumber);
6201
+ endOfdirectoryRecord.uint16(diskNumber);
6202
+ endOfdirectoryRecord.uint16(filesLength);
6203
+ endOfdirectoryRecord.uint16(filesLength);
6204
+ endOfdirectoryRecord.uint32(directoryDataLength);
6205
+ endOfdirectoryRecord.uint32(directoryOffset);
6206
+ endOfdirectoryRecord.uint16(commentLength);
6207
+ await writeData(writer, endOfdirectoryRecord.array);
5786
6208
  if (commentLength) {
5787
6209
  await writeData(writer, comment);
5788
6210
  }
5789
6211
  }
5790
6212
 
6213
+ function createRecordWriter(length) {
6214
+ const array = new Uint8Array(length);
6215
+ const view = getDataView(array);
6216
+ let offset = 0;
6217
+ return {
6218
+ array,
6219
+ uint8: value => { setUint8(view, offset, value); offset += 1; },
6220
+ uint16: value => { setUint16(view, offset, value); offset += 2; },
6221
+ uint32: value => { setUint32(view, offset, value); offset += 4; },
6222
+ uint64: value => { setBigUint64(view, offset, BigInt(value)); offset += 8; },
6223
+ bytes: value => { arraySet(array, value, offset); offset += getLength(value); },
6224
+ skip: count => offset += count
6225
+ };
6226
+ }
6227
+
6228
+ function getSegmentOffset(zipWriter, writer) {
6229
+ return zipWriter.offset - writer.diskOffset - (writer.diskNumber ? zipWriter.initialOffset : 0);
6230
+ }
6231
+
5791
6232
  async function writeData(writer, array) {
5792
6233
  const { writable } = writer;
5793
6234
  const streamWriter = writable.getWriter();
@@ -5800,12 +6241,40 @@ async function writeData(writer, array) {
5800
6241
  }
5801
6242
  }
5802
6243
 
6244
+ async function flushBufferedData(readable, writer, signal, onChunkWritten) {
6245
+ const streamWriter = writer.writable.getWriter();
6246
+ try {
6247
+ await readable.pipeTo(new WritableStream({
6248
+ async write(chunk) {
6249
+ await streamWriter.ready;
6250
+ await streamWriter.write(chunk);
6251
+ onChunkWritten(getLength(chunk));
6252
+ }
6253
+ }), { preventClose: true, preventAbort: true, signal });
6254
+ } finally {
6255
+ streamWriter.releaseLock();
6256
+ }
6257
+ }
6258
+
5803
6259
  function getTimeNTFS(date) {
5804
6260
  if (date) {
5805
6261
  return ((BigInt(date.getTime()) + BigInt(11644473600000)) * BigInt(10000));
5806
6262
  }
5807
6263
  }
5808
6264
 
6265
+ function getTimeUnix(date) {
6266
+ return Math.floor(date.getTime() / 1000);
6267
+ }
6268
+
6269
+ // the extended timestamp extra field stores dates as signed 32-bit time_t values
6270
+ function inUnixTimeRange(timeUnix) {
6271
+ return timeUnix >= MIN_UNIX_TIME && timeUnix <= MAX_UNIX_TIME;
6272
+ }
6273
+
6274
+ function clampUnixTime(timeUnix) {
6275
+ return Math.min(MAX_UNIX_TIME, Math.max(MIN_UNIX_TIME, timeUnix));
6276
+ }
6277
+
5809
6278
  function getOptionValue(zipWriter, options, name, defaultValue) {
5810
6279
  const result = options[name] === UNDEFINED_VALUE ? zipWriter.options[name] : options[name];
5811
6280
  return result === UNDEFINED_VALUE ? defaultValue : result;
@@ -5836,7 +6305,7 @@ function arraySet(array, typedArray, offset) {
5836
6305
  }
5837
6306
 
5838
6307
  function getDataView(array) {
5839
- return new DataView(array.buffer);
6308
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
5840
6309
  }
5841
6310
 
5842
6311
  function getLength(...arrayLikes) {
@@ -5852,30 +6321,39 @@ function getHeaderArrayData({
5852
6321
  uncompressedSize,
5853
6322
  compressedSize,
5854
6323
  lastModDate,
6324
+ rawLastModDate,
5855
6325
  rawFilename,
5856
6326
  zip64CompressedSize,
5857
6327
  zip64UncompressedSize,
5858
6328
  extraFieldLength
5859
6329
  }) {
5860
- const headerArray = new Uint8Array(HEADER_SIZE - 4);
6330
+ const headerRecord = createRecordWriter(HEADER_SIZE - 4);
6331
+ const headerArray = headerRecord.array;
5861
6332
  const headerView = getDataView(headerArray);
5862
- setUint16(headerView, 0, version);
5863
- setUint16(headerView, 2, bitFlag);
5864
- setUint16(headerView, 4, compressionMethod);
5865
- const dateArray = new Uint32Array(1);
5866
- const dateView = getDataView(dateArray);
5867
- setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
5868
- setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
5869
- const rawLastModDate = dateArray[0];
5870
- setUint32(headerView, 6, rawLastModDate);
6333
+ headerRecord.uint16(version);
6334
+ headerRecord.uint16(bitFlag);
6335
+ headerRecord.uint16(compressionMethod);
6336
+ if (rawLastModDate === UNDEFINED_VALUE) {
6337
+ const dateArray = new Uint32Array(1);
6338
+ const dateView = getDataView(dateArray);
6339
+ setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
6340
+ setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
6341
+ rawLastModDate = dateArray[0];
6342
+ }
6343
+ headerRecord.uint32(rawLastModDate);
6344
+ headerRecord.skip(4);
5871
6345
  if (zip64CompressedSize || compressedSize !== UNDEFINED_VALUE) {
5872
- setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, zip64CompressedSize ? MAX_32_BITS : compressedSize);
6346
+ headerRecord.uint32(zip64CompressedSize ? MAX_32_BITS : compressedSize);
6347
+ } else {
6348
+ headerRecord.skip(4);
5873
6349
  }
5874
6350
  if (zip64UncompressedSize || uncompressedSize !== UNDEFINED_VALUE) {
5875
- setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6351
+ headerRecord.uint32(zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6352
+ } else {
6353
+ headerRecord.skip(4);
5876
6354
  }
5877
- setUint16(headerView, 22, getLength(rawFilename));
5878
- setUint16(headerView, 24, extraFieldLength);
6355
+ headerRecord.uint16(getLength(rawFilename));
6356
+ headerRecord.uint16(extraFieldLength);
5879
6357
  return {
5880
6358
  headerArray,
5881
6359
  headerView,
@@ -5976,7 +6454,7 @@ try {
5976
6454
  // ignored
5977
6455
  }
5978
6456
 
5979
- const A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function g(g){let B;g({wasmURI:()=>(B||(B="data:application/wasm;base64,"+(g=>{g=(g=>{const B=(g=(g+"").replace(/[^A-Za-z0-9+/=]/g,"")).length,E=[];for(let I=0;B>I;I+=4){const B=A.indexOf(g[I])<<18|A.indexOf(g[I+1])<<12|(63&A.indexOf(g[I+2]))<<6|63&A.indexOf(g[I+3]);E.push(B>>16&255),"="!==g[I+2]&&E.push(B>>8&255),"="!==g[I+3]&&E.push(255&B);}return new Uint8Array(E)})(g);let B=new Uint8Array(1024),E=0;for(let A=0;A<g.length;){const C=g[A++];if(128&C){const Q=3+(127&C),D=g[A++]<<8|g[A++],o=E-D;I(E+Q);for(let A=0;Q>A;A++)B[E++]=B[o+A];}else {const Q=C;I(E+Q);for(let I=0;Q>I&&A<g.length;I++)B[E++]=g[A++];}}return (g=>{let B="";const E=g.length;let I=0;for(;E>I+2;I+=3){const E=g[I]<<16|g[I+1]<<8|g[I+2];B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+A[63&E];}const C=E-I;if(1===C){const E=g[I]<<16;B+=A[E>>18&63]+A[E>>12&63]+"==";}else if(2===C){const E=g[I]<<16|g[I+1]<<8;B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+"=";}return B})(new Uint8Array(B.buffer.slice(0,E)));function I(A){if(B.length<A){let g=2*B.length;for(;A>g;)g*=2;const I=new Uint8Array(g);I.set(B.subarray(0,E)),B=I;}}})("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BAGZgAAEAVmAAAQB2YAABAE5gAAEAbmAAAQBeYAABAH5gAAEAQWAAAQBhYAABAFFgAAEAcWAAAQBJYAABAGlgAAEAWWAAAQB5YAABAEVgAAEAZWAAAQBVYAABAHVgAAEATWAAAQBtYAABAF1gAAEAfWAAAQBDYAABAGNgAAEAU2AAAQBzYAABIARMwIArYAABAFtgAAEAe2AAAQBHYAABAGdgAAEAV2AAAQB3YAABAE9gAAEAb2AAAQBfYAABAH9gAAEAROAAMIFEwEJAJOAAAgBk4AACAFTgAAIAVOAAAgB04AACAHTgAAIATOAAAgBM4AACAGzgAAIAbOAAAgBc4AACAFzgAAIAfOAAAgB84AACAELgAAIgBDagAQCgAAEgAAIAUuAAAgBS4AACAHLgAAIAcuAAAgBK4AACAErgAAIAauAAAgBq4AACAFrgAAIAWuAAAgB64AACAHrgAAIARuAAAgBG4AACAGbgAAIAZuAAAgBW4AACAFbgAAIAduAAAgB24AACAE7gAAIATuAAAgBu4AACAG7gAAIAXuAAAgBe4AACAH7gAAIAfuAAAiBA7YBB4AACAGHgAAIAYeAAAgBR4AACAFHgAAIAceAAAgBx4AACAEngAAIASeAAAgBp4AACAGngAAIAWeAAAgBZ4AACAHngAAIAeeAAAgBF4AACAEXgAAIAZeAAAgBl4AACAFXgAAIAVeAAAgB14AACAHXgAAIATeAAAgBN4AACAG3gAAIAbeAAAgBd4AACAF3gAAIAfeAAAgB94AACAEPgAAIAQ+AAAgBj4AACAGPgAAIAU+AAAgBT4AACAHPgAAIAc+AAAgBL4AACAEvgAAIAa+AAAgBr4AACAFvgAAIAW+AAAgB74AACAHvgAAIAR+AAAgBH4AACAGfgAAIAZ+AAAgBX4AACAFfgAAIAd+AAAgB34AACAE/gAAIAT+AAAgBv4AACAG/gAAIAX+AAAgBf4AACAH/gAAIAf+AAAiBBAoBQIAABAEggAAEAWCAAAQBEIAABAFQgAAEATCAAAQBcIIFVgMHAEiAAAQBKIAABAFogAAEARiAAAQBWIAABAE4gAAEAXiAAAQBBIAABAFEgAAEASSAAAQBZIAABAEUgAAEAVSAAAQBNIAABAF0gAAEAQOAAEIBg4AABAFDgAAEAcOAAAQBI4AABAGjgAAEAWOAAAQB44AABIC+K4AAdIECxgEFgABcAQWCBUoBFIAABAEMgAAEARyAAASAvlaABEQBBYIGBAEaggXqAQWAA9QBBYADuAEFgAOcgE92gAAEARGAAAQBCYAABAEZgAAEgQACARWAAAQBDYAABAEdgAAEgL59gAKkgQZAAQWAAiyBBaYBBYABtAEFgD3fAxsLTYMfuYcABIC+rooABIEHUYkABAEEjAAEAQWKAAQEQbAcC4C9CosAS40AO4UALwEGhAAEgQWIgQAEgQEKgQAEgQGSgQAEgIS2ggAEAQuEAAQBDIQABIAF24FHeQTgHQsjhQBfhQXLAhARgAVtBgcJBgoFC4A6uAQNAg4BgAclBJQeC2mFAJCFAIiFAICFAHiBAGiBAFyBBh8BEIAABAEUgAAEARiAAAQBHIAABAEggAAEASiAAAQBMIAABAE4gAAEAUCAAAQBUIAABIEGvQFwgAAEAYCAAAQBoIAABAHAgAAEAeCAAG8DHwtyjQBvgQBrgQBngQBjgQBfgQBbgQBXgQBTgQBPgQBLgQBHgQBDgQE8AYCvAEGAUc0CC22BAMcBBIAAAgEIgAAEgQEzgQJLARCAAA6DAAyBnqyAqmuEACSBB3OBAE8BCIAACIEAGIUADIEIt4MADAEggQCUgDKEgQBrAYCBCC8BBIMADIA/SAoBABAMAEGRIQv/gCUfgMDAgIKxBQgJCQoKgEk3gAABAQ2AAAEBDoAAAQEPgAABARCEAAEBEYQAAQEShAABAROEAAEBFIwAAQEVjAABARaMAAEBF4wAAQEYnAABARmcAAEBGpwAAQEbmwABARyBffsEBAQFBYHB1QEHgAABAQiEAAGAXSqCAAEBCowAAYAnsooAAYEBMJkAAYEBTJkAAYEBaLkAAYEBpLkAAYIDdYABzoUBvI0BqJ0BkLwBgAIbHLwAAQEdvAABgA9PgH05A9AqAQ==")),B)});}
6457
+ const A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function g(g){let B;g({wasmURI:()=>(B||(B="data:application/wasm;base64,"+(g=>{g=(g=>{const B=(g=(g+"").replace(/[^A-Za-z0-9+/=]/g,"")).length,E=[];for(let I=0;B>I;I+=4){const B=A.indexOf(g[I])<<18|A.indexOf(g[I+1])<<12|(63&A.indexOf(g[I+2]))<<6|63&A.indexOf(g[I+3]);E.push(B>>16&255),"="!==g[I+2]&&E.push(B>>8&255),"="!==g[I+3]&&E.push(255&B);}return new Uint8Array(E)})(g);let B=new Uint8Array(1024),E=0;for(let A=0;A<g.length;){const C=g[A++];if(128&C){const Q=3+(127&C),Y=g[A++]<<8|g[A++],D=E-Y;I(E+Q);for(let A=0;Q>A;A++)B[E++]=B[D+A];}else {const Q=C;I(E+Q);for(let I=0;Q>I&&A<g.length;I++)B[E++]=g[A++];}}return (g=>{let B="";const E=g.length;let I=0;for(;E>I+2;I+=3){const E=g[I]<<16|g[I+1]<<8|g[I+2];B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+A[63&E];}const C=E-I;if(1===C){const E=g[I]<<16;B+=A[E>>18&63]+A[E>>12&63]+"==";}else if(2===C){const E=g[I]<<16|g[I+1]<<8;B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+"=";}return B})(new Uint8Array(B.buffer.slice(0,E)));function I(A){if(B.length<A){let g=2*B.length;for(;A>g;)g*=2;const I=new Uint8Array(g);I.set(B.subarray(0,E)),B=I;}}})("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BAEVgAAEAZWAAAQBVYAABAHVgAAEATWAAAQBtYAABAF1gAAEAfWAAAQBDYAABAGNgAAEAU2AAAQBzYAABIAN6AIArYAABAFtgAAEAe2AAAQBHYAABAGdgAAEAV2AAAQB3YAABAE9gAAEAb2AAAQBfYAABAH9gAAEAROAAMIFEwEJAJOAAAgBk4AACAFTgAAIAVOAAAgB04AACAHTgAAIATOAAAgBM4AACAGzgAAIAbOAAAgBc4AACAFzgAAIAfOAAAgB84AACAELgAAIgA2LgAQCgAAEgAAIAUuAAAgBS4AACAHLgAAIAcuAAAgBK4AACAErgAAIAauAAAgBq4AACAFrgAAIAWuAAAgB64AACAHrgAAIARuAAAgBG4AACAGbgAAIAZuAAAgBW4AACAFbgAAIAduAAAgB24AACAE7gAAIATuAAAgBu4AACAG7gAAIAXuAAAgBe4AACAH7gAAIAfuAAAiBA7YBB4AACAGHgAAIAYeAAAgBR4AACAFHgAAIAceAAAgBx4AACAEngAAIASeAAAgBp4AACAGngAAIAWeAAAgBZ4AACAHngAAIAeeAAAgBF4AACAEXgAAIAZeAAAgBl4AACAFXgAAIAVeAAAgB14AACAHXgAAIATeAAAgBN4AACAG3gAAIAbeAAAgBd4AACAF3gAAIAfeAAAgB94AACAEPgAAIAQ+AAAgBj4AACAGPgAAIAU+AAAgBT4AACAHPgAAIAc+AAAgBL4AACAEvgAAIAa+AAAgBr4AACAFvgAAIAW+AAAgB74AACAHvgAAIAR+AAAgBH4AACAGfgAAIAZ+AAAgBX4AACAFfgAAIAd+AAAgB34AACAE/gAAIAT+AAAgBv4AACAG/gAAIAX+AAAgBf4AACAH/gAAIAf+AAAiBBAoBQIAABAEggAAEAWCAAAQBEIAABAFQgAAEATCAAAQBcIIFVgMHAEiAAAQBKIAABAFogAAEARiAAAQBWIAABAE4gAAEAXiAAAQBBIAABAFEgAAEASSAAAQBZIAABAEUgAAEAVSAAAQBNIAABAF0gAAEAQOAAEIBg4AABAFDgAAEAcOAAAQBI4AABAGjgAAEAWOAAAQB44AABIC/A4AAdIECxgEFgABcAQWCBUoBFIAABAEMgAAEARyAAAQBAoAABAESgAAEgQYEARqCBeoBBYAD1AEFgAO4AQWAA5yATGqAAAQBEYAABAEJgAAEARmAAASBAAIBFYAABAENgAAEAR2AAASAv26AAqSBBkABBYACLIEFpgEFgAG0AQWAOroDGwtNgxx6hwAEAQKMAASBB1GJAAQBBIwABAEFigAEBEGwHAuAveGLAEuNADuFAC8BBoQABIEFiIEABIEBCoEABIEBkoEABICFfIIABAELhAAEAQyEAASABduBRGIE4B0LI4UAX4UFywIQEYAFbQYHCQYKBQuAN44EDQIOAYAHJQSUHgtphQCQhQCIhQCAhQB4gQBogQBcgQYfARCAAAQBFIAABAEYgAAEARyAAAQBIIAABAEogAAEATCAAAQBOIAABAFAgAAEAVCAAASBBr0BcIAABAGAgAAEAaCAAAQBwIAABAHggABvAx8Lco0Ab4EAa4EAZ4EAY4EAX4EAW4EAV4EAU4EAT4EAS4EAR4EAQ4EBPAGArwBBgE7BAgttgQDHAQSAAAIBCIAABIEBM4ECSwEQgAAOgwAMgZ97gKs6hAAkgQdzgQBPAQiAAAiBABiFAAyBCLeDAAwBIIEAlIAvUoEAawGAgQgvAQSDAAyAPCIKAQAQDABBkSEL/4Ah4AEDgpzlBQgJCQoKgEYggAABAQ2AAAEBDoAAAQEPgAABARCEAAEBEYQAAQEShAABAROEAAEBFIwAAQEVjAABARaMAAEBF4wAAQEYnAABARmcAAEBGpwAAQEbmwABARyBfrkEBAQFBYHCrAEHgAABAQiEAAGAWjqCAAEBCowAAYAkc4oAAYEBMJkAAYEBTJkAAYEBaLkAAYEBpLkAAYIDdYABzoUBvI0BqJ0BkLwBgAIbHLwAAQEdvAABgLyTgH3yA9AqAQ==")),B)});}
5980
6458
 
5981
6459
  /*
5982
6460
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -6026,46 +6504,54 @@ function _make(isCompress, type, options = {}) {
6026
6504
 
6027
6505
  return new TransformStream({
6028
6506
  start() {
6029
- let result;
6030
- this.out = malloc(outBufferSize);
6031
- this.in = malloc(inBufferSize);
6032
- this.inBufferSize = inBufferSize;
6033
- this._scratch = new Uint8Array(outBufferSize);
6034
- if (isCompress) {
6035
- this._process = wasm.deflate_process;
6036
- this._last_consumed = wasm.deflate_last_consumed;
6037
- this._end = wasm.deflate_end;
6038
- this.streamHandle = wasm.deflate_new();
6039
- if (type === "gzip") {
6040
- result = wasm.deflate_init_gzip(this.streamHandle, level);
6041
- } else if (type === "deflate-raw") {
6042
- result = wasm.deflate_init_raw(this.streamHandle, level);
6043
- } else {
6044
- result = wasm.deflate_init(this.streamHandle, level);
6507
+ try {
6508
+ let result;
6509
+ this.out = malloc(outBufferSize);
6510
+ this.in = malloc(inBufferSize);
6511
+ this.inBufferSize = inBufferSize;
6512
+ if (!this.out || !this.in) {
6513
+ throw new Error("allocation failed");
6045
6514
  }
6046
- } else {
6047
- if (type === "deflate64-raw") {
6048
- this._process = wasm.inflate9_process;
6049
- this._last_consumed = wasm.inflate9_last_consumed;
6050
- this._end = wasm.inflate9_end;
6051
- this.streamHandle = wasm.inflate9_new();
6052
- result = wasm.inflate9_init_raw(this.streamHandle);
6515
+ this._scratch = new Uint8Array(outBufferSize);
6516
+ if (isCompress) {
6517
+ this._process = wasm.deflate_process;
6518
+ this._last_consumed = wasm.deflate_last_consumed;
6519
+ this._end = wasm.deflate_end;
6520
+ this.streamHandle = wasm.deflate_new();
6521
+ if (type === "gzip") {
6522
+ result = wasm.deflate_init_gzip(this.streamHandle, level);
6523
+ } else if (type === "deflate-raw") {
6524
+ result = wasm.deflate_init_raw(this.streamHandle, level);
6525
+ } else {
6526
+ result = wasm.deflate_init(this.streamHandle, level);
6527
+ }
6053
6528
  } else {
6054
- this._process = wasm.inflate_process;
6055
- this._last_consumed = wasm.inflate_last_consumed;
6056
- this._end = wasm.inflate_end;
6057
- this.streamHandle = wasm.inflate_new();
6058
- if (type === "deflate-raw") {
6059
- result = wasm.inflate_init_raw(this.streamHandle);
6060
- } else if (type === "gzip") {
6061
- result = wasm.inflate_init_gzip(this.streamHandle);
6529
+ if (type === "deflate64-raw") {
6530
+ this._process = wasm.inflate9_process;
6531
+ this._last_consumed = wasm.inflate9_last_consumed;
6532
+ this._end = wasm.inflate9_end;
6533
+ this.streamHandle = wasm.inflate9_new();
6534
+ result = wasm.inflate9_init_raw(this.streamHandle);
6062
6535
  } else {
6063
- result = wasm.inflate_init(this.streamHandle);
6536
+ this._process = wasm.inflate_process;
6537
+ this._last_consumed = wasm.inflate_last_consumed;
6538
+ this._end = wasm.inflate_end;
6539
+ this.streamHandle = wasm.inflate_new();
6540
+ if (type === "deflate-raw") {
6541
+ result = wasm.inflate_init_raw(this.streamHandle);
6542
+ } else if (type === "gzip") {
6543
+ result = wasm.inflate_init_gzip(this.streamHandle);
6544
+ } else {
6545
+ result = wasm.inflate_init(this.streamHandle);
6546
+ }
6064
6547
  }
6065
6548
  }
6066
- }
6067
- if (result !== 0) {
6068
- throw new Error("init failed:" + result);
6549
+ if (result !== 0) {
6550
+ throw new Error("init failed:" + result);
6551
+ }
6552
+ } catch (error) {
6553
+ disposeStream(this);
6554
+ throw error;
6069
6555
  }
6070
6556
  },
6071
6557
  transform(chunk, controller) {
@@ -6082,9 +6568,13 @@ function _make(isCompress, type, options = {}) {
6082
6568
  if (!this.in || this.inBufferSize < toRead) {
6083
6569
  if (this.in && free) {
6084
6570
  free(this.in);
6571
+ this.in = 0;
6085
6572
  }
6086
6573
  this.in = malloc(toRead);
6087
6574
  this.inBufferSize = toRead;
6575
+ if (!this.in) {
6576
+ throw new Error("allocation failed");
6577
+ }
6088
6578
  }
6089
6579
  heap.set(buffer.subarray(offset, offset + toRead), this.in);
6090
6580
  const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
@@ -6107,15 +6597,7 @@ function _make(isCompress, type, options = {}) {
6107
6597
  offset += consumed;
6108
6598
  }
6109
6599
  } catch (error) {
6110
- if (this._end && this.streamHandle) {
6111
- this._end(this.streamHandle);
6112
- }
6113
- if (this.in && free) {
6114
- free(this.in);
6115
- }
6116
- if (this.out && free) {
6117
- free(this.out);
6118
- }
6600
+ disposeStream(this);
6119
6601
  controller.error(error);
6120
6602
  }
6121
6603
  },
@@ -6146,21 +6628,35 @@ function _make(isCompress, type, options = {}) {
6146
6628
  } catch (error) {
6147
6629
  controller.error(error);
6148
6630
  } finally {
6149
- if (this._end && this.streamHandle) {
6150
- const result = this._end(this.streamHandle);
6151
- if (result !== 0) {
6152
- controller.error(new Error("end error:" + result));
6153
- }
6154
- }
6155
- if (this.in && free) {
6156
- free(this.in);
6157
- }
6158
- if (this.out && free) {
6159
- free(this.out);
6631
+ const result = disposeStream(this);
6632
+ if (result !== 0) {
6633
+ controller.error(new Error("end error:" + result));
6160
6634
  }
6161
6635
  }
6636
+ },
6637
+ cancel() {
6638
+ // release the stream handle and buffers when the pipeline is aborted,
6639
+ // they would be leaked in the process-lifetime wasm heap otherwise
6640
+ disposeStream(this);
6162
6641
  }
6163
6642
  });
6643
+
6644
+ function disposeStream(state) {
6645
+ let endResult = 0;
6646
+ if (state.streamHandle && state._end) {
6647
+ endResult = state._end(state.streamHandle);
6648
+ }
6649
+ state.streamHandle = 0;
6650
+ if (state.in && free) {
6651
+ free(state.in);
6652
+ }
6653
+ state.in = 0;
6654
+ if (state.out && free) {
6655
+ free(state.out);
6656
+ }
6657
+ state.out = 0;
6658
+ return endResult;
6659
+ }
6164
6660
  }
6165
6661
 
6166
6662
  class CompressionStreamZlib {
@@ -6330,12 +6826,15 @@ function terminateWorkersAndModule() {
6330
6826
  */
6331
6827
 
6332
6828
 
6829
+ const ERR_ENTRY_EXISTS = "Entry filename already exists";
6830
+ const ERR_READABLE_CONSUMED = "Readable stream already consumed";
6831
+
6333
6832
  class ZipEntry {
6334
6833
 
6335
6834
  constructor(fs, name, params, parent) {
6336
6835
  const zipEntry = this;
6337
6836
  if (fs.root && parent && parent.getChildByName(name)) {
6338
- throw new Error("Entry filename already exists");
6837
+ throw new Error(ERR_ENTRY_EXISTS);
6339
6838
  }
6340
6839
  if (!params) {
6341
6840
  params = {};
@@ -6345,13 +6844,17 @@ class ZipEntry {
6345
6844
  name,
6346
6845
  data: params.data,
6347
6846
  options: params.options,
6348
- id: fs.entries.length,
6847
+ id: fs.entryIdCounter++,
6349
6848
  parent,
6350
6849
  children: [],
6351
6850
  uncompressedSize: params.uncompressedSize || 0,
6352
6851
  passThrough: params.passThrough
6353
6852
  });
6354
- fs.entries.push(zipEntry);
6853
+ // detached entries (e.g. clones) are not registered until they are attached,
6854
+ // otherwise they could never be garbage collected
6855
+ if (parent || !fs.root) {
6856
+ fs.entries[zipEntry.id] = zipEntry;
6857
+ }
6355
6858
  if (parent) {
6356
6859
  zipEntry.parent.children.push(zipEntry);
6357
6860
  }
@@ -6389,7 +6892,7 @@ class ZipEntry {
6389
6892
  rename(name) {
6390
6893
  const parent = this.parent;
6391
6894
  if (parent && parent.getChildByName(name)) {
6392
- throw new Error("Entry filename already exists");
6895
+ throw new Error(ERR_ENTRY_EXISTS);
6393
6896
  } else {
6394
6897
  this.name = name;
6395
6898
  }
@@ -6428,16 +6931,17 @@ class ZipFileEntry extends ZipEntry {
6428
6931
  }
6429
6932
 
6430
6933
  isPasswordProtected() {
6431
- return this.data.encrypted;
6934
+ return Boolean(this.data && this.data.encrypted);
6432
6935
  }
6433
6936
 
6434
6937
  async checkPassword(password, options = {}) {
6435
6938
  const zipEntry = this;
6436
6939
  if (zipEntry.isPasswordProtected()) {
6437
- options.password = password;
6438
- options.checkPasswordOnly = true;
6439
6940
  try {
6440
- await zipEntry.data.getData(null, options);
6941
+ await zipEntry.data.getData(null, Object.assign({}, options, {
6942
+ password,
6943
+ checkPasswordOnly: true
6944
+ }));
6441
6945
  return true;
6442
6946
  } catch (error) {
6443
6947
  if (error.message == ERR_INVALID_PASSWORD) {
@@ -6471,8 +6975,15 @@ class ZipFileEntry extends ZipEntry {
6471
6975
  return this.getData({ writable }, options);
6472
6976
  }
6473
6977
 
6474
- getArrayBuffer(options) {
6475
- return this.data.arrayBuffer(options);
6978
+ async getArrayBuffer(options) {
6979
+ // this.data may be a string, a Uint8Array, a data URI or a Blob depending on how the entry
6980
+ // was created, so retrieve the bytes through getUint8Array rather than assuming a Blob; this
6981
+ // also applies the options (password, signal, onprogress...) like the other getData() getters
6982
+ const array = await this.getUint8Array(options);
6983
+ // return the backing buffer directly when the array spans it, slicing the exact bytes otherwise
6984
+ return array.byteOffset || array.byteLength != array.buffer.byteLength
6985
+ ? array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength)
6986
+ : array.buffer;
6476
6987
  }
6477
6988
 
6478
6989
  replaceBlob(blob) {
@@ -6514,7 +7025,7 @@ class ZipFileEntry extends ZipEntry {
6514
7025
  replaceReadable(readable) {
6515
7026
  Object.assign(this, {
6516
7027
  data: null,
6517
- Reader: function () { return { readable }; },
7028
+ Reader: getReadableReader(readable),
6518
7029
  Writer: null,
6519
7030
  reader: null
6520
7031
  });
@@ -6530,7 +7041,7 @@ class ZipDirectoryEntry extends ZipEntry {
6530
7041
 
6531
7042
  clone(deepClone) {
6532
7043
  const zipEntry = this;
6533
- const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name);
7044
+ const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name, zipEntry);
6534
7045
  if (deepClone) {
6535
7046
  clonedEntry.children = zipEntry.children.map(child => {
6536
7047
  const childClone = child.clone(deepClone);
@@ -6604,7 +7115,7 @@ class ZipDirectoryEntry extends ZipEntry {
6604
7115
 
6605
7116
  addReadable(name, readable, options = {}) {
6606
7117
  return addChild(this, name, {
6607
- Reader: function () { return { readable }; },
7118
+ Reader: getReadableReader(readable),
6608
7119
  options
6609
7120
  });
6610
7121
  }
@@ -6618,6 +7129,7 @@ class ZipDirectoryEntry extends ZipEntry {
6618
7129
  }
6619
7130
 
6620
7131
  addFile(file, options = {}) {
7132
+ options = Object.assign({}, options);
6621
7133
  if (!options.lastModDate) {
6622
7134
  options.lastModDate = new Date(file.lastModified);
6623
7135
  }
@@ -6684,11 +7196,15 @@ class ZipDirectoryEntry extends ZipEntry {
6684
7196
  try {
6685
7197
  const path = entry.filename.split("/");
6686
7198
  const name = path.pop();
6687
- path.forEach((pathPart, pathIndex) => {
7199
+ path.forEach(pathPart => {
6688
7200
  const previousParent = parent;
6689
7201
  parent = parent.getChildByName(pathPart);
6690
- if (!parent) {
6691
- parent = new ZipDirectoryEntry(this.fs, pathPart, { data: pathIndex == path.length - 1 ? entry : null }, previousParent);
7202
+ if (parent) {
7203
+ if (!parent.directory) {
7204
+ throw new Error(ERR_ENTRY_EXISTS);
7205
+ }
7206
+ } else {
7207
+ parent = new ZipDirectoryEntry(this.fs, pathPart, { data: null }, previousParent);
6692
7208
  importedEntries.push(parent);
6693
7209
  }
6694
7210
  });
@@ -6699,6 +7215,22 @@ class ZipDirectoryEntry extends ZipEntry {
6699
7215
  uncompressedSize: entry.uncompressedSize,
6700
7216
  passThrough: options.passThrough
6701
7217
  }));
7218
+ } else {
7219
+ let directoryEntry = parent;
7220
+ if (name) {
7221
+ directoryEntry = parent.getChildByName(name);
7222
+ if (directoryEntry) {
7223
+ if (!directoryEntry.directory) {
7224
+ throw new Error(ERR_ENTRY_EXISTS);
7225
+ }
7226
+ } else {
7227
+ directoryEntry = new ZipDirectoryEntry(this.fs, name, { data: null }, parent);
7228
+ importedEntries.push(directoryEntry);
7229
+ }
7230
+ }
7231
+ if (directoryEntry != this && !directoryEntry.data) {
7232
+ directoryEntry.data = entry;
7233
+ }
6702
7234
  }
6703
7235
  } catch (error) {
6704
7236
  try {
@@ -6714,14 +7246,15 @@ class ZipDirectoryEntry extends ZipEntry {
6714
7246
  return importedEntries;
6715
7247
  }
6716
7248
 
6717
- async exportZip(writer, options) {
7249
+ async exportZip(writer, options = {}) {
6718
7250
  const zipEntry = this;
7251
+ options = Object.assign({}, options);
6719
7252
  if (options.bufferedWrite === UNDEFINED_VALUE) {
6720
7253
  options.bufferedWrite = true;
6721
7254
  }
6722
- await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
7255
+ const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
6723
7256
  const zipWriter = new ZipWriter(writer, options);
6724
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options);
7257
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
6725
7258
  await zipWriter.close();
6726
7259
  return writer.getData ? writer.getData() : writer.writable;
6727
7260
  }
@@ -6767,7 +7300,15 @@ class FS {
6767
7300
 
6768
7301
  remove(entry) {
6769
7302
  detach(entry);
6770
- this.entries[entry.id] = null;
7303
+ const removedEntries = [entry];
7304
+ while (removedEntries.length) {
7305
+ const removedEntry = removedEntries.pop();
7306
+ this.entries[removedEntry.id] = null;
7307
+ for (const child of removedEntry.children) {
7308
+ removedEntries.push(child);
7309
+ }
7310
+ }
7311
+ entry.parent = UNDEFINED_VALUE;
6771
7312
  }
6772
7313
 
6773
7314
  move(entry, destination) {
@@ -6777,12 +7318,17 @@ class FS {
6777
7318
  if (destination.directory) {
6778
7319
  if (!destination.isDescendantOf(entry)) {
6779
7320
  if (entry != destination) {
6780
- if (destination.getChildByName(entry.name)) {
6781
- throw new Error("Entry filename already exists");
7321
+ const existingChild = destination.getChildByName(entry.name);
7322
+ if (existingChild) {
7323
+ if (existingChild != entry) {
7324
+ throw new Error(ERR_ENTRY_EXISTS);
7325
+ }
7326
+ } else {
7327
+ detach(entry);
7328
+ entry.parent = destination;
7329
+ destination.children.push(entry);
7330
+ registerEntries(this, entry);
6782
7331
  }
6783
- detach(entry);
6784
- entry.parent = destination;
6785
- destination.children.push(entry);
6786
7332
  }
6787
7333
  } else {
6788
7334
  throw new Error("Entry is a ancestor of target entry");
@@ -6799,6 +7345,11 @@ class FS {
6799
7345
  for (let index = 0; node && index < path.length; index++) {
6800
7346
  node = node.getChildByName(path[index]);
6801
7347
  }
7348
+ if (!node) {
7349
+ // exclude detached entries, e.g. clones registered in `entries` but not attached
7350
+ node = this.entries.find(entry => entry && (entry == this.root || entry.isDescendantOf(this.root)) &&
7351
+ entry.getRelativeName() == fullname);
7352
+ }
6802
7353
  return node;
6803
7354
  }
6804
7355
 
@@ -6880,6 +7431,7 @@ class FS {
6880
7431
  }
6881
7432
 
6882
7433
  importZip(reader, options) {
7434
+ resetFS(this);
6883
7435
  return this.root.importZip(reader, options);
6884
7436
  }
6885
7437
 
@@ -6899,6 +7451,10 @@ class FS {
6899
7451
  return this.root.exportWritable(writable, options);
6900
7452
  }
6901
7453
 
7454
+ exportZip(writer, options) {
7455
+ return this.root.exportZip(writer, options);
7456
+ }
7457
+
6902
7458
  isPasswordProtected() {
6903
7459
  return this.root.isPasswordProtected();
6904
7460
  }
@@ -6912,15 +7468,26 @@ const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
6912
7468
 
6913
7469
  function getTotalSize(entries, propertyName) {
6914
7470
  let size = 0;
6915
- entries.forEach(process);
7471
+ const pendingEntries = Array.from(entries);
7472
+ while (pendingEntries.length) {
7473
+ const entry = pendingEntries.pop();
7474
+ size += entry[propertyName] || 0;
7475
+ for (const child of entry.children) {
7476
+ pendingEntries.push(child);
7477
+ }
7478
+ }
6916
7479
  return size;
7480
+ }
6917
7481
 
6918
- function process(entry) {
6919
- size += entry[propertyName];
6920
- if (entry.children) {
6921
- entry.children.forEach(process);
7482
+ function getReadableReader(readable) {
7483
+ let consumed;
7484
+ return function () {
7485
+ if (consumed) {
7486
+ throw new Error(ERR_READABLE_CONSUMED);
6922
7487
  }
6923
- }
7488
+ consumed = true;
7489
+ return { readable };
7490
+ };
6924
7491
  }
6925
7492
 
6926
7493
  function getZipBlobReader(options) {
@@ -6935,7 +7502,7 @@ function getZipBlobReader(options) {
6935
7502
  async init() {
6936
7503
  const zipBlobReader = this;
6937
7504
  zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
6938
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options));
7505
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
6939
7506
  zipBlobReader.data = data;
6940
7507
  zipBlobReader.blobReader = new BlobReader(data);
6941
7508
  super.init();
@@ -6948,29 +7515,41 @@ function getZipBlobReader(options) {
6948
7515
  }
6949
7516
 
6950
7517
  async function initReaders(entry, options) {
6951
- if (entry.children.length) {
6952
- await Promise.all(entry.children.map(async child => {
7518
+ const fileEntries = [];
7519
+ const pendingEntries = [entry];
7520
+ // per-export map so concurrent exports do not share (and lock) the same readers
7521
+ const readers = new Map();
7522
+ while (pendingEntries.length) {
7523
+ const pendingEntry = pendingEntries.pop();
7524
+ for (const child of pendingEntry.children) {
6953
7525
  if (child.directory) {
6954
- await initReaders(child, options);
7526
+ pendingEntries.push(child);
6955
7527
  } else {
6956
- const reader = child.reader = new child.Reader(child.data, options);
6957
- try {
6958
- await initStream(reader);
6959
- } catch (error) {
6960
- try {
6961
- error.entryId = child.id;
6962
- error.cause = {
6963
- entry: child
6964
- };
6965
- } catch {
6966
- // ignored
6967
- }
6968
- throw error;
6969
- }
6970
- child.uncompressedSize = reader.size;
7528
+ fileEntries.push(child);
6971
7529
  }
6972
- }));
7530
+ }
6973
7531
  }
7532
+ await Promise.all(fileEntries.map(async child => {
7533
+ const reader = child.reader = new child.Reader(child.data, options);
7534
+ readers.set(child, reader);
7535
+ try {
7536
+ await initStream(reader);
7537
+ } catch (error) {
7538
+ try {
7539
+ error.entryId = child.id;
7540
+ error.cause = {
7541
+ entry: child
7542
+ };
7543
+ } catch {
7544
+ // ignored
7545
+ }
7546
+ throw error;
7547
+ }
7548
+ if (reader.size !== UNDEFINED_VALUE) {
7549
+ child.uncompressedSize = reader.size;
7550
+ }
7551
+ }));
7552
+ return readers;
6974
7553
  }
6975
7554
 
6976
7555
  function detach(entry) {
@@ -6984,7 +7563,7 @@ function detach(entry) {
6984
7563
  }
6985
7564
  }
6986
7565
 
6987
- async function exportZip(zipWriter, entry, totalSize, options) {
7566
+ async function exportZip(zipWriter, entry, totalSize, options, readers) {
6988
7567
  const selectedEntry = entry;
6989
7568
  const entryOffsets = new Map();
6990
7569
  await process(zipWriter, entry);
@@ -6994,7 +7573,11 @@ async function exportZip(zipWriter, entry, totalSize, options) {
6994
7573
 
6995
7574
  async function exportChild() {
6996
7575
  if (options.bufferedWrite) {
6997
- await Promise.allSettled(entry.children.map(processChild));
7576
+ const results = await Promise.allSettled(entry.children.map(processChild));
7577
+ const errorResult = results.find(result => result.status == "rejected");
7578
+ if (errorResult) {
7579
+ throw errorResult.reason;
7580
+ }
6998
7581
  } else {
6999
7582
  for (const child of entry.children) {
7000
7583
  await processChild(child);
@@ -7049,7 +7632,7 @@ async function exportZip(zipWriter, entry, totalSize, options) {
7049
7632
  });
7050
7633
  }
7051
7634
  }
7052
- await zipWriter.add(name, child.reader, Object.assign({}, options, zipEntryOptions, childOptions, {
7635
+ await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
7053
7636
  directory: child.directory,
7054
7637
  onprogress: async indexProgress => {
7055
7638
  if (options.onprogress) {
@@ -7098,7 +7681,7 @@ function addFileSystemHandle(zipEntry, handle, options) {
7098
7681
  }
7099
7682
  } catch (error) {
7100
7683
  const message = error.message + (handle ? " (" + handle.name + ")" : "");
7101
- throw new Error(message);
7684
+ throw new Error(message, { cause: error });
7102
7685
  }
7103
7686
  }
7104
7687
  return addedEntries;
@@ -7158,9 +7741,21 @@ async function transformToFileSystemhandles(entry) {
7158
7741
 
7159
7742
  function resetFS(fs) {
7160
7743
  fs.entries = [];
7744
+ fs.entryIdCounter = 0;
7161
7745
  fs.root = new ZipDirectoryEntry(fs);
7162
7746
  }
7163
7747
 
7748
+ function registerEntries(fs, entry) {
7749
+ const pendingEntries = [entry];
7750
+ while (pendingEntries.length) {
7751
+ const pendingEntry = pendingEntries.pop();
7752
+ fs.entries[pendingEntry.id] = pendingEntry;
7753
+ for (const child of pendingEntry.children) {
7754
+ pendingEntries.push(child);
7755
+ }
7756
+ }
7757
+ }
7758
+
7164
7759
  function addChild(parent, name, params, directory) {
7165
7760
  if (parent.directory) {
7166
7761
  return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
@@ -8836,6 +9431,7 @@ exports.BlobReader = BlobReader;
8836
9431
  exports.BlobWriter = BlobWriter;
8837
9432
  exports.Data64URIReader = Data64URIReader;
8838
9433
  exports.Data64URIWriter = Data64URIWriter;
9434
+ exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
8839
9435
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
8840
9436
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
8841
9437
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
@@ -8845,6 +9441,7 @@ exports.ERR_EOCDR_NOT_FOUND = ERR_EOCDR_NOT_FOUND;
8845
9441
  exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND;
8846
9442
  exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE;
8847
9443
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
9444
+ exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
8848
9445
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
8849
9446
  exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT;
8850
9447
  exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME;
@@ -8857,8 +9454,9 @@ exports.ERR_INVALID_VERSION = ERR_INVALID_VERSION;
8857
9454
  exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND;
8858
9455
  exports.ERR_OVERLAPPING_ENTRY = ERR_OVERLAPPING_ENTRY;
8859
9456
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9457
+ exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
8860
9458
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
8861
- exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION;
9459
+ exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
8862
9460
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
8863
9461
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
8864
9462
  exports.ERR_ZIP_NOT_EMPTY = ERR_ZIP_NOT_EMPTY;