@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/dist/zip-fs.js CHANGED
@@ -50,6 +50,7 @@
50
50
  const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
51
51
  const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
52
52
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50;
53
+ const CENTRAL_FILE_HEADER_LENGTH = 46;
53
54
  const END_OF_CENTRAL_DIR_LENGTH = 22;
54
55
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20;
55
56
  const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56;
@@ -97,9 +98,11 @@
97
98
  const DIRECTORY_SIGNATURE = "/";
98
99
 
99
100
  const HEADER_SIZE = 30;
101
+ const HEADER_OFFSET_VERSION = 0;
100
102
  const HEADER_OFFSET_SIGNATURE = 10;
101
103
  const HEADER_OFFSET_COMPRESSED_SIZE = 14;
102
104
  const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
105
+ const LOCAL_HEADER_COMMON_OFFSET = 4;
103
106
 
104
107
  const MAX_DATE = new Date(2107, 11, 31);
105
108
  const MIN_DATE = new Date(1980, 0, 1);
@@ -154,6 +157,7 @@
154
157
  chunkSize: 64 * 1024,
155
158
  maxWorkers,
156
159
  terminateWorkerTimeout: 5000,
160
+ workerStarvationTimeout: 5000,
157
161
  useWebWorkers: true,
158
162
  useCompressionStream: true,
159
163
  CompressionStream: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
@@ -176,6 +180,7 @@
176
180
  chunkSize,
177
181
  maxWorkers,
178
182
  terminateWorkerTimeout,
183
+ workerStarvationTimeout,
179
184
  useCompressionStream,
180
185
  useWebWorkers,
181
186
  CompressionStream,
@@ -191,6 +196,7 @@
191
196
  setIfDefined("chunkSize", chunkSize);
192
197
  setIfDefined("maxWorkers", maxWorkers);
193
198
  setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
199
+ setIfDefined("workerStarvationTimeout", workerStarvationTimeout);
194
200
  setIfDefined("useCompressionStream", useCompressionStream);
195
201
  setIfDefined("useWebWorkers", useWebWorkers);
196
202
  setIfDefined("CompressionStream", CompressionStream);
@@ -205,7 +211,7 @@
205
211
  }
206
212
  }
207
213
 
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: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)}});}
214
+ 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)}});}
209
215
 
210
216
  /*
211
217
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -954,37 +960,6 @@
954
960
  }
955
961
  };
956
962
 
957
- /**
958
- * Random values
959
- * @namespace
960
- */
961
- const random = {
962
- /**
963
- * Generate random words with pure js, cryptographically not as strong & safe as native implementation.
964
- * @param {TypedArray} typedArray The array to fill.
965
- * @return {TypedArray} The random values.
966
- */
967
- getRandomValues(typedArray) {
968
- const words = new Uint32Array(typedArray.buffer);
969
- const r = (m_w) => {
970
- let m_z = 0x3ade68b1;
971
- const mask = 0xffffffff;
972
- return function () {
973
- m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
974
- m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
975
- const result = ((((m_z << 0x10) + m_w) & mask) / 0x100000000) + .5;
976
- return result * (Math.random() > .5 ? 1 : -1);
977
- };
978
- };
979
- for (let i = 0, rcache; i < typedArray.length; i += 4) {
980
- const _r = r((rcache || Math.random()) * 0x100000000);
981
- rcache = _r() * 0x3ade67b7;
982
- words[i / 4] = (_r() * 0x100000000) | 0;
983
- }
984
- return typedArray;
985
- }
986
- };
987
-
988
963
  /** @fileOverview CTR mode implementation.
989
964
  *
990
965
  * Special thanks to Roy Nicholson for pointing out a bug in our
@@ -1215,12 +1190,15 @@
1215
1190
  const ERR_INVALID_PASSWORD = "Invalid password";
1216
1191
  const ERR_INVALID_SIGNATURE = "Invalid signature";
1217
1192
  const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
1193
+ const ERR_UNSUPPORTED_CRYPTO_API = "Crypto API not supported";
1218
1194
 
1219
1195
  function getRandomValues(array) {
1220
1196
  if (GET_RANDOM_VALUES_SUPPORTED) {
1221
1197
  return crypto.getRandomValues(array);
1222
1198
  } else {
1223
- return random.getRandomValues(array);
1199
+ // all supported runtimes expose crypto.getRandomValues; failing hard beats
1200
+ // silently generating predictable encryption salts
1201
+ throw new Error(ERR_UNSUPPORTED_CRYPTO_API);
1224
1202
  }
1225
1203
  }
1226
1204
 
@@ -1279,13 +1257,12 @@
1279
1257
 
1280
1258
  class AESDecryptionStream extends TransformStream {
1281
1259
 
1282
- constructor({ password, rawPassword, signed, encryptionStrength, checkPasswordOnly }) {
1260
+ constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly }) {
1283
1261
  super({
1284
1262
  start() {
1285
1263
  Object.assign(this, {
1286
1264
  ready: new Promise(resolve => this.resolveReady = resolve),
1287
1265
  password: encodePassword(password, rawPassword),
1288
- signed,
1289
1266
  strength: encryptionStrength - 1,
1290
1267
  pending: new Uint8Array()
1291
1268
  });
@@ -1314,7 +1291,6 @@
1314
1291
  },
1315
1292
  async flush(controller) {
1316
1293
  const {
1317
- signed,
1318
1294
  ctr,
1319
1295
  hmac,
1320
1296
  pending,
@@ -1331,13 +1307,15 @@
1331
1307
  const decryptedChunk = ctr.update(encryptedChunk);
1332
1308
  decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
1333
1309
  }
1334
- if (signed) {
1335
- const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1336
- for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1337
- if (signature[indexSignature] != originalSignature[indexSignature]) {
1338
- throw new Error(ERR_INVALID_SIGNATURE);
1339
- }
1340
- }
1310
+ const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1311
+ // branch-free comparison: accumulate the differences instead of
1312
+ // short-circuiting on the first mismatching byte
1313
+ let invalidSignature = pending.length < SIGNATURE_LENGTH ? 1 : 0;
1314
+ for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1315
+ invalidSignature |= signature[indexSignature] ^ originalSignature[indexSignature];
1316
+ }
1317
+ if (invalidSignature) {
1318
+ throw new Error(ERR_INVALID_SIGNATURE);
1341
1319
  }
1342
1320
  controller.enqueue(decryptedChunkArray);
1343
1321
  }
@@ -1409,11 +1387,11 @@
1409
1387
  hmac,
1410
1388
  pending
1411
1389
  } = aesCrypto;
1412
- const inputLength = input.length - paddingEnd;
1413
1390
  if (pending.length) {
1414
1391
  input = concat(pending, input);
1415
- output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
1416
1392
  }
1393
+ const inputLength = input.length - paddingEnd;
1394
+ output = expand(output, paddingStart + (inputLength - (inputLength % BLOCK_LENGTH)));
1417
1395
  let offset;
1418
1396
  for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
1419
1397
  const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
@@ -1561,21 +1539,24 @@
1561
1539
 
1562
1540
  class ZipCryptoDecryptionStream extends TransformStream {
1563
1541
 
1564
- constructor({ password, passwordVerification, checkPasswordOnly }) {
1542
+ constructor({ password, rawPassword, passwordVerification, checkPasswordOnly }) {
1565
1543
  super({
1566
1544
  start() {
1567
1545
  Object.assign(this, {
1568
1546
  password,
1547
+ rawPassword,
1569
1548
  passwordVerification
1570
1549
  });
1571
- createKeys(this, password);
1550
+ createKeys(this, password, rawPassword);
1572
1551
  },
1573
1552
  transform(chunk, controller) {
1574
1553
  const zipCrypto = this;
1575
- if (zipCrypto.password) {
1554
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1576
1555
  const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
1577
- zipCrypto.password = null;
1578
- if (decryptedHeader.at(-1) != zipCrypto.passwordVerification) {
1556
+ zipCrypto.password = zipCrypto.rawPassword = null;
1557
+ // verify the password with a branch-free comparison of the verification byte, mirroring
1558
+ // the constant-time AES HMAC signature check
1559
+ if ((decryptedHeader.at(-1) ^ zipCrypto.passwordVerification) != 0) {
1579
1560
  throw new Error(ERR_INVALID_PASSWORD);
1580
1561
  }
1581
1562
  chunk = chunk.subarray(HEADER_LENGTH);
@@ -1592,21 +1573,22 @@
1592
1573
 
1593
1574
  class ZipCryptoEncryptionStream extends TransformStream {
1594
1575
 
1595
- constructor({ password, passwordVerification }) {
1576
+ constructor({ password, rawPassword, passwordVerification }) {
1596
1577
  super({
1597
1578
  start() {
1598
1579
  Object.assign(this, {
1599
1580
  password,
1581
+ rawPassword,
1600
1582
  passwordVerification
1601
1583
  });
1602
- createKeys(this, password);
1584
+ createKeys(this, password, rawPassword);
1603
1585
  },
1604
1586
  transform(chunk, controller) {
1605
1587
  const zipCrypto = this;
1606
1588
  let output;
1607
1589
  let offset;
1608
- if (zipCrypto.password) {
1609
- zipCrypto.password = null;
1590
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1591
+ zipCrypto.password = zipCrypto.rawPassword = null;
1610
1592
  const header = getRandomValues(new Uint8Array(HEADER_LENGTH));
1611
1593
  header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification;
1612
1594
  output = new Uint8Array(chunk.length + header.length);
@@ -1641,25 +1623,31 @@
1641
1623
  return output;
1642
1624
  }
1643
1625
 
1644
- function createKeys(target, password) {
1626
+ function createKeys(target, password, rawPassword) {
1645
1627
  const keys = [0x12345678, 0x23456789, 0x34567890];
1646
1628
  Object.assign(target, {
1647
1629
  keys,
1648
1630
  crcKey0: new Crc32(keys[0]),
1649
1631
  crcKey2: new Crc32(keys[2])
1650
1632
  });
1651
- for (let index = 0; index < password.length; index++) {
1652
- updateKeys(target, password.charCodeAt(index));
1633
+ if (rawPassword) {
1634
+ for (let index = 0; index < rawPassword.length; index++) {
1635
+ updateKeys(target, rawPassword[index]);
1636
+ }
1637
+ } else {
1638
+ for (let index = 0; index < password.length; index++) {
1639
+ updateKeys(target, password.charCodeAt(index));
1640
+ }
1653
1641
  }
1654
1642
  }
1655
1643
 
1656
1644
  function updateKeys(target, byte) {
1657
- let [key0, key1, key2] = target.keys;
1645
+ let [, key1] = target.keys;
1658
1646
  target.crcKey0.append([byte]);
1659
- key0 = ~target.crcKey0.get();
1647
+ const key0 = ~target.crcKey0.get();
1660
1648
  key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
1661
1649
  target.crcKey2.append([key1 >>> 24]);
1662
- key2 = ~target.crcKey2.get();
1650
+ const key2 = ~target.crcKey2.get();
1663
1651
  target.keys = [key0, key1, key2];
1664
1652
  }
1665
1653
 
@@ -1706,6 +1694,7 @@
1706
1694
 
1707
1695
 
1708
1696
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
1697
+ const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
1709
1698
  const FORMAT_DEFLATE_RAW = "deflate-raw";
1710
1699
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
1711
1700
 
@@ -1762,6 +1751,7 @@
1762
1751
  }
1763
1752
  if (compressed) {
1764
1753
  readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
1754
+ readable = mapInflateStreamError(readable);
1765
1755
  }
1766
1756
  if ((!encrypted || zipCrypto) && signed) {
1767
1757
  crc32Stream = new Crc32Stream();
@@ -1812,6 +1802,37 @@
1812
1802
  return readable.pipeThrough(transformStream);
1813
1803
  }
1814
1804
 
1805
+ // DecompressionStream implementations can fail with a message-less TypeError on malformed
1806
+ // input; give these errors an identifiable message (errors raised by the other stages of
1807
+ // the pipeline, e.g. ERR_INVALID_PASSWORD, always carry a message and pass through as-is)
1808
+ function mapInflateStreamError(readable) {
1809
+ const reader = readable.getReader();
1810
+ return new ReadableStream({
1811
+ async pull(controller) {
1812
+ let result;
1813
+ try {
1814
+ result = await reader.read();
1815
+ } catch (error) {
1816
+ if (error && error.message) {
1817
+ throw error;
1818
+ }
1819
+ const mappedError = new Error(ERR_INVALID_COMPRESSED_DATA);
1820
+ mappedError.cause = error;
1821
+ throw mappedError;
1822
+ }
1823
+ const { value, done } = result;
1824
+ if (done) {
1825
+ controller.close();
1826
+ } else {
1827
+ controller.enqueue(value);
1828
+ }
1829
+ },
1830
+ cancel(reason) {
1831
+ return reader.cancel(reason);
1832
+ }
1833
+ });
1834
+ }
1835
+
1815
1836
  /*
1816
1837
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
1817
1838
 
@@ -1841,6 +1862,7 @@
1841
1862
  */
1842
1863
 
1843
1864
 
1865
+ const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
1844
1866
  const MESSAGE_EVENT_TYPE = "message";
1845
1867
  const MESSAGE_START = "start";
1846
1868
  const MESSAGE_PULL = "pull";
@@ -1909,6 +1931,9 @@
1909
1931
 
1910
1932
  constructor(chunkSize) {
1911
1933
  let pendingChunk;
1934
+ if (!(chunkSize >= 1)) {
1935
+ chunkSize = DEFAULT_CHUNK_SIZE$1;
1936
+ }
1912
1937
  super({
1913
1938
  transform,
1914
1939
  flush(controller) {
@@ -1926,12 +1951,12 @@
1926
1951
  chunk = newChunk;
1927
1952
  pendingChunk = null;
1928
1953
  }
1929
- if (chunk.length > chunkSize) {
1930
- controller.enqueue(chunk.slice(0, chunkSize));
1931
- transform(chunk.slice(chunkSize), controller);
1932
- } else {
1933
- pendingChunk = chunk;
1954
+ let offset = 0;
1955
+ while (chunk.length - offset > chunkSize) {
1956
+ controller.enqueue(chunk.slice(offset, offset + chunkSize));
1957
+ offset += chunkSize;
1934
1958
  }
1959
+ pendingChunk = offset ? chunk.slice(offset) : chunk;
1935
1960
  }
1936
1961
  }
1937
1962
  }
@@ -1966,8 +1991,10 @@
1966
1991
 
1967
1992
 
1968
1993
  const MODULE_WORKER_OPTIONS = { type: "module" };
1994
+ const ERROR_EVENT_TYPE = "error";
1995
+ const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
1969
1996
 
1970
- let webWorkerSupported, webWorkerURI, webWorkerOptions;
1997
+ let webWorkerSupported, webWorkerSource, webWorkerURI, webWorkerOptions;
1971
1998
  let transferStreamsSupported = true;
1972
1999
  try {
1973
2000
  transferStreamsSupported = typeof structuredClone == FUNCTION_TYPE && structuredClone(new DOMException("", "AbortError")).code !== UNDEFINED_VALUE;
@@ -1986,8 +2013,9 @@
1986
2013
  const { signal } = streamOptions;
1987
2014
  Object.assign(workerData, {
1988
2015
  busy: true,
2016
+ generation: (workerData.generation || 0) + 1,
1989
2017
  readable: readable
1990
- .pipeThrough(new ChunkStream(config.chunkSize))
2018
+ .pipeThrough(new ChunkStream(getChunkSize(config)))
1991
2019
  .pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
1992
2020
  writable,
1993
2021
  options: Object.assign({}, options),
@@ -2010,15 +2038,17 @@
2010
2038
  });
2011
2039
  },
2012
2040
  onTaskFinished() {
2013
- const { resolveTerminated } = workerData;
2014
- if (resolveTerminated) {
2015
- workerData.resolveTerminated = null;
2016
- workerData.terminated = true;
2017
- workerData.worker.terminate();
2018
- resolveTerminated();
2041
+ if (workerData.busy) {
2042
+ const { resolveTerminated } = workerData;
2043
+ if (resolveTerminated) {
2044
+ workerData.resolveTerminated = null;
2045
+ workerData.terminated = true;
2046
+ workerData.worker.terminate();
2047
+ resolveTerminated();
2048
+ }
2049
+ workerData.busy = false;
2050
+ onTaskFinished(workerData);
2019
2051
  }
2020
- workerData.busy = false;
2021
- onTaskFinished(workerData);
2022
2052
  }
2023
2053
  });
2024
2054
  if (webWorkerSupported === UNDEFINED_VALUE) {
@@ -2087,6 +2117,7 @@
2087
2117
  }
2088
2118
  Object.assign(workerData, {
2089
2119
  worker,
2120
+ terminated: false,
2090
2121
  interface: {
2091
2122
  run: () => runWebWorker(workerData, { chunkSize, wasmURI, baseURI })
2092
2123
  }
@@ -2141,37 +2172,85 @@
2141
2172
  result
2142
2173
  });
2143
2174
  const { readable, options } = workerData;
2144
- const { writable, closed } = watchClosedStream(workerData.writable);
2145
- const streamsTransferred = sendMessage({
2146
- type: MESSAGE_START,
2147
- options,
2148
- config,
2149
- readable,
2150
- writable
2151
- }, workerData);
2175
+ const { writable, closed, abortPipe } = watchClosedStream(workerData.writable);
2176
+ let streamsTransferred;
2177
+ try {
2178
+ streamsTransferred = sendMessage({
2179
+ type: MESSAGE_START,
2180
+ options,
2181
+ config,
2182
+ readable,
2183
+ writable
2184
+ }, workerData);
2185
+ } catch (error) {
2186
+ abortPipe();
2187
+ try {
2188
+ await closed;
2189
+ } catch {
2190
+ // ignored
2191
+ }
2192
+ workerData.onTaskFinished();
2193
+ throw error;
2194
+ }
2152
2195
  if (!streamsTransferred) {
2153
2196
  Object.assign(workerData, {
2154
2197
  reader: readable.getReader(),
2155
2198
  writer: writable.getWriter()
2156
2199
  });
2157
2200
  }
2158
- const resultValue = await result;
2159
- if (!streamsTransferred) {
2160
- await writable.getWriter().close();
2201
+ try {
2202
+ const resultValue = await result;
2203
+ await closeWritable();
2204
+ await closed;
2205
+ return resultValue;
2206
+ } catch (error) {
2207
+ await closeWritable();
2208
+ // unblock the pipe watcher if the worker died before closing its end of the stream
2209
+ abortPipe();
2210
+ try {
2211
+ await closed;
2212
+ } catch {
2213
+ // ignored
2214
+ }
2215
+ throw error;
2216
+ }
2217
+
2218
+ async function closeWritable() {
2219
+ if (!streamsTransferred && !writable.locked) {
2220
+ try {
2221
+ await writable.getWriter().close();
2222
+ } catch {
2223
+ // ignored
2224
+ }
2225
+ }
2161
2226
  }
2162
- await closed;
2163
- return resultValue;
2164
2227
  }
2165
2228
 
2166
2229
  function watchClosedStream(writableSource) {
2230
+ const abortController = new AbortController();
2167
2231
  const { writable, readable } = new TransformStream();
2168
- const closed = readable.pipeTo(writableSource, { preventClose: true });
2169
- return { writable, closed };
2232
+ const closed = readable.pipeTo(writableSource, { preventClose: true, preventAbort: true, signal: abortController.signal });
2233
+ // the pipe can fail before `closed` is awaited (e.g. the destination write fails);
2234
+ // mark the rejection as handled so it cannot kill the process in the meantime
2235
+ closed.catch(() => { });
2236
+ return { writable, closed, abortPipe: () => abortController.abort() };
2237
+ }
2238
+
2239
+ function terminateWorker$1(workerData) {
2240
+ const { worker } = workerData;
2241
+ if (worker) {
2242
+ try {
2243
+ worker.terminate();
2244
+ } catch {
2245
+ // ignored
2246
+ }
2247
+ }
2248
+ workerData.interface = null;
2170
2249
  }
2171
2250
 
2172
2251
  function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true) {
2173
2252
  let worker, resolvedURI, resolvedOptions;
2174
- if (webWorkerURI === UNDEFINED_VALUE) {
2253
+ if (webWorkerURI === UNDEFINED_VALUE || webWorkerSource !== url) {
2175
2254
  // deno-lint-ignore valid-typeof
2176
2255
  const isFunctionURI = typeof url == FUNCTION_TYPE;
2177
2256
  if (isFunctionURI) {
@@ -2228,16 +2307,36 @@
2228
2307
  }
2229
2308
  }
2230
2309
  }
2310
+ webWorkerSource = url;
2231
2311
  webWorkerURI = resolvedURI;
2232
2312
  webWorkerOptions = resolvedOptions;
2233
2313
  } else {
2234
2314
  worker = new Worker(webWorkerURI, webWorkerOptions);
2235
2315
  }
2236
2316
  worker.addEventListener(MESSAGE_EVENT_TYPE, event => onMessage(event, workerData));
2317
+ worker.addEventListener(ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2318
+ worker.addEventListener(MESSAGE_ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2237
2319
  return worker;
2238
2320
  }
2239
2321
 
2240
- function sendMessage(message, { worker, writer, onTaskFinished, transferStreams }) {
2322
+ function onWorkerError(event, workerData) {
2323
+ if (event.preventDefault) {
2324
+ event.preventDefault();
2325
+ }
2326
+ const { rejectResult, writer, onTaskFinished } = workerData;
2327
+ // the worker is unusable (e.g. its script failed to load); terminate it and
2328
+ // fail the current task instead of letting it hang forever
2329
+ terminateWorker$1(workerData);
2330
+ if (rejectResult) {
2331
+ rejectResult(event.error || new Error(event.message || ERROR_EVENT_TYPE));
2332
+ if (writer) {
2333
+ writer.releaseLock();
2334
+ }
2335
+ onTaskFinished();
2336
+ }
2337
+ }
2338
+
2339
+ function sendMessage(message, { worker, writer, transferStreams }) {
2241
2340
  try {
2242
2341
  const { value, readable, writable } = message;
2243
2342
  const transferables = [];
@@ -2271,14 +2370,16 @@
2271
2370
  if (writer) {
2272
2371
  writer.releaseLock();
2273
2372
  }
2274
- onTaskFinished();
2275
2373
  throw error;
2276
2374
  }
2277
2375
  }
2278
2376
 
2279
2377
  async function onMessage({ data }, workerData) {
2280
2378
  const { type, value, messageId, result, error } = data;
2281
- const { reader, writer, resolveResult, rejectResult, onTaskFinished } = workerData;
2379
+ const { reader, writer, resolveResult, rejectResult, onTaskFinished, generation } = workerData;
2380
+ // continuations below can settle after the worker slot has been reassigned to a new
2381
+ // task (e.g. a pending pull read failing late); they must not touch the new task
2382
+ const stale = () => workerData.generation != generation;
2282
2383
  try {
2283
2384
  if (error) {
2284
2385
  const { message, stack, code, name, outputSize } = error;
@@ -2288,23 +2389,32 @@
2288
2389
  } else {
2289
2390
  if (type == MESSAGE_PULL) {
2290
2391
  const { value, done } = await reader.read();
2291
- sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2392
+ if (!stale()) {
2393
+ sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2394
+ }
2292
2395
  }
2293
2396
  if (type == MESSAGE_DATA) {
2294
2397
  await writer.ready;
2295
2398
  await writer.write(new Uint8Array(value));
2296
- sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2399
+ if (!stale()) {
2400
+ sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2401
+ }
2297
2402
  }
2298
2403
  if (type == MESSAGE_CLOSE) {
2299
2404
  close(null, result);
2300
2405
  }
2301
2406
  }
2302
2407
  } catch (error) {
2303
- sendMessage({ type: MESSAGE_CLOSE, messageId }, workerData);
2304
- close(error);
2408
+ if (!stale()) {
2409
+ terminateWorker$1(workerData);
2410
+ close(error);
2411
+ }
2305
2412
  }
2306
2413
 
2307
2414
  function close(error, result) {
2415
+ if (stale()) {
2416
+ return;
2417
+ }
2308
2418
  if (error) {
2309
2419
  rejectResult(error);
2310
2420
  } else {
@@ -2348,6 +2458,8 @@
2348
2458
 
2349
2459
  let pool = [];
2350
2460
  const pendingRequests = [];
2461
+ let starvationTimeout;
2462
+ let starvationDelay;
2351
2463
 
2352
2464
  let indexWorker = 0;
2353
2465
 
@@ -2374,14 +2486,20 @@
2374
2486
  pool.push(workerData);
2375
2487
  return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
2376
2488
  } else {
2377
- return new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
2489
+ return new Promise(resolve => {
2490
+ pendingRequests.push({ resolve, stream, workerOptions });
2491
+ starvationDelay = config.workerStarvationTimeout;
2492
+ armStarvationTimeout();
2493
+ });
2378
2494
  }
2379
2495
  }
2380
2496
 
2381
2497
  function onTaskFinished(workerData) {
2498
+ clearStarvationTimeout();
2382
2499
  if (pendingRequests.length) {
2383
2500
  const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2384
2501
  resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
2502
+ armStarvationTimeout();
2385
2503
  } else if (workerData.worker) {
2386
2504
  clearTerminateTimeout(workerData);
2387
2505
  terminateWorker(workerData, workerOptions);
@@ -2391,6 +2509,34 @@
2391
2509
  }
2392
2510
  }
2393
2511
 
2512
+ function armStarvationTimeout() {
2513
+ if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
2514
+ starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
2515
+ }
2516
+ }
2517
+
2518
+ function clearStarvationTimeout() {
2519
+ if (starvationTimeout) {
2520
+ clearTimeout(starvationTimeout);
2521
+ starvationTimeout = null;
2522
+ }
2523
+ }
2524
+
2525
+ function onWorkerStarvation() {
2526
+ starvationTimeout = null;
2527
+ if (pendingRequests.length) {
2528
+ const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2529
+ const inlineWorkerOptions = Object.assign({}, workerOptions, { useWebWorkers: false, workerURI: UNDEFINED_VALUE });
2530
+ resolve(new CodecWorker({}, stream, inlineWorkerOptions, onInlineTaskFinished));
2531
+ armStarvationTimeout();
2532
+ }
2533
+ }
2534
+
2535
+ function onInlineTaskFinished() {
2536
+ clearStarvationTimeout();
2537
+ armStarvationTimeout();
2538
+ }
2539
+
2394
2540
  function terminateWorker(workerData, workerOptions) {
2395
2541
  const { config } = workerOptions;
2396
2542
  const { terminateWorkerTimeout } = config;
@@ -2461,6 +2607,7 @@
2461
2607
 
2462
2608
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
2463
2609
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
2610
+ const HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
2464
2611
  const HTTP_HEADER_CONTENT_RANGE = "Content-Range";
2465
2612
  const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges";
2466
2613
  const HTTP_HEADER_RANGE = "Range";
@@ -2585,7 +2732,7 @@
2585
2732
 
2586
2733
  writeUint8Array(array) {
2587
2734
  const writer = this;
2588
- let indexArray = 0;
2735
+ let indexArray;
2589
2736
  let dataString = writer.pending;
2590
2737
  const delta = writer.pending.length;
2591
2738
  writer.pending = "";
@@ -2595,12 +2742,10 @@
2595
2742
  for (; indexArray < array.length; indexArray++) {
2596
2743
  writer.pending += String.fromCharCode(array[indexArray]);
2597
2744
  }
2598
- if (dataString.length) {
2599
- if (dataString.length > 2) {
2600
- writer.data += btoa(dataString);
2601
- } else {
2602
- writer.pending += dataString;
2603
- }
2745
+ if (dataString.length > 2) {
2746
+ writer.data += btoa(dataString);
2747
+ } else {
2748
+ writer.pending = dataString + writer.pending;
2604
2749
  }
2605
2750
  }
2606
2751
 
@@ -2647,6 +2792,9 @@
2647
2792
  }
2648
2793
  });
2649
2794
  writer.blob = new Response(transformStream.readable, { headers }).blob();
2795
+ // mark early rejections (e.g. aborted pipe) as handled; awaiting getData() still
2796
+ // surfaces them
2797
+ writer.blob.catch(() => { });
2650
2798
  }
2651
2799
 
2652
2800
  getData() {
@@ -2731,7 +2879,8 @@
2731
2879
  preventHeadRequest,
2732
2880
  useRangeHeader,
2733
2881
  forceRangeRequests,
2734
- combineSizeEocd
2882
+ combineSizeEocd,
2883
+ fetch
2735
2884
  } = options;
2736
2885
  options = Object.assign({}, options);
2737
2886
  delete options.preventHeadRequest;
@@ -2739,13 +2888,15 @@
2739
2888
  delete options.forceRangeRequests;
2740
2889
  delete options.combineSizeEocd;
2741
2890
  delete options.useXHR;
2891
+ delete options.fetch;
2742
2892
  Object.assign(httpReader, {
2743
2893
  url,
2744
2894
  options,
2745
2895
  preventHeadRequest,
2746
2896
  useRangeHeader,
2747
2897
  forceRangeRequests,
2748
- combineSizeEocd
2898
+ combineSizeEocd,
2899
+ fetch
2749
2900
  });
2750
2901
  }
2751
2902
 
@@ -2764,7 +2915,10 @@
2764
2915
  throw new Error(ERR_HTTP_RANGE);
2765
2916
  } else {
2766
2917
  if (combineSizeEocd) {
2767
- httpReader.eocdCache = new Uint8Array(await response.arrayBuffer());
2918
+ const eocdCache = new Uint8Array(await response.arrayBuffer());
2919
+ if (response.status == 206 && eocdCache.length == END_OF_CENTRAL_DIR_LENGTH) {
2920
+ httpReader.eocdCache = eocdCache;
2921
+ }
2768
2922
  }
2769
2923
  let contentSize;
2770
2924
  const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
@@ -2810,7 +2964,18 @@
2810
2964
  if (response.status != 206) {
2811
2965
  throw new Error(ERR_HTTP_RANGE);
2812
2966
  }
2813
- return new Uint8Array(await response.arrayBuffer());
2967
+ const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
2968
+ if (contentRangeHeader) {
2969
+ const rangeStart = Number(contentRangeHeader.trim().split(/[\s-]+/)[1]);
2970
+ if (!Number.isNaN(rangeStart) && rangeStart != index) {
2971
+ throw new Error(ERR_HTTP_RANGE);
2972
+ }
2973
+ }
2974
+ const data = new Uint8Array(await response.arrayBuffer());
2975
+ if (data.length != length) {
2976
+ throw new Error(ERR_HTTP_RANGE);
2977
+ }
2978
+ return data;
2814
2979
  }
2815
2980
  } else {
2816
2981
  const { data } = httpReader;
@@ -2847,9 +3012,9 @@
2847
3012
  async function getRequestData(httpReader, sendRequest) {
2848
3013
  const response = await sendRequest(HTTP_METHOD_GET, httpReader, getHeaders(httpReader));
2849
3014
  httpReader.data = new Uint8Array(await response.arrayBuffer());
2850
- if (!httpReader.size) {
2851
- httpReader.size = httpReader.data.length;
2852
- }
3015
+ // the downloaded content is authoritative, e.g. the Content-Length response header
3016
+ // of the HEAD request can be the encoded size when the content is compressed
3017
+ httpReader.size = httpReader.data.length;
2853
3018
  }
2854
3019
 
2855
3020
  async function getContentLength(httpReader, sendRequest, getRequestData) {
@@ -2858,7 +3023,7 @@
2858
3023
  } else {
2859
3024
  const response = await sendRequest(HTTP_METHOD_HEAD, httpReader, getHeaders(httpReader));
2860
3025
  const contentLength = response.headers.get(HTTP_HEADER_CONTENT_LENGTH);
2861
- if (contentLength) {
3026
+ if (contentLength && !response.headers.get(HTTP_HEADER_CONTENT_ENCODING)) {
2862
3027
  httpReader.size = Number(contentLength);
2863
3028
  } else {
2864
3029
  await getRequestData(httpReader, httpReader.options);
@@ -2866,8 +3031,8 @@
2866
3031
  }
2867
3032
  }
2868
3033
 
2869
- async function sendFetchRequest(method, { options, url }, headers) {
2870
- const response = await fetch(url, Object.assign({}, options, { method, headers }));
3034
+ async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
3035
+ const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
2871
3036
  if (response.status < 400) {
2872
3037
  return response;
2873
3038
  } else {
@@ -2913,7 +3078,8 @@
2913
3078
  super();
2914
3079
  Object.assign(this, {
2915
3080
  url,
2916
- reader: options.useXHR ? new XHRReader(url, options) : new FetchReader(url, options)
3081
+ // an explicit fetch implementation takes precedence over useXHR
3082
+ reader: options.useXHR && !options.fetch ? new XHRReader(url, options) : new FetchReader(url, options)
2917
3083
  });
2918
3084
  }
2919
3085
 
@@ -2938,8 +3104,7 @@
2938
3104
  class HttpRangeReader extends HttpReader {
2939
3105
 
2940
3106
  constructor(url, options = {}) {
2941
- options.useRangeHeader = true;
2942
- super(url, options);
3107
+ super(url, Object.assign({}, options, { useRangeHeader: true }));
2943
3108
  }
2944
3109
  }
2945
3110
 
@@ -3013,7 +3178,7 @@
3013
3178
  reader.lastDiskNumber = 0;
3014
3179
  reader.lastDiskOffset = 0;
3015
3180
  await Promise.all(readers.map(async (diskReader, indexDiskReader) => {
3016
- await diskReader.init();
3181
+ await initStream(diskReader);
3017
3182
  if (indexDiskReader != readers.length - 1) {
3018
3183
  reader.lastDiskOffset += diskReader.size;
3019
3184
  }
@@ -3097,14 +3262,26 @@
3097
3262
  writer.diskOffset += diskSourceWriter.size;
3098
3263
  writer.diskNumber++;
3099
3264
  diskWriter = null;
3100
- await this.write(chunk.subarray(availableSize));
3265
+ // the next disk is not opened yet but its space is available; leaving a
3266
+ // stale value here would force a new disk for every subsequent write
3267
+ writer.availableSize = writer.maxSize;
3268
+ if (chunk.length > availableSize) {
3269
+ await this.write(chunk.subarray(availableSize));
3270
+ }
3101
3271
  } else {
3102
3272
  await writeChunk(chunk);
3103
3273
  }
3104
3274
  },
3105
3275
  async close() {
3106
- await diskWriter.ready;
3107
- await closeDisk();
3276
+ if (diskWriter) {
3277
+ await diskWriter.ready;
3278
+ await closeDisk();
3279
+ }
3280
+ },
3281
+ async abort(reason) {
3282
+ if (diskWriter) {
3283
+ await diskWriter.abort(reason);
3284
+ }
3108
3285
  }
3109
3286
  });
3110
3287
  Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
@@ -3119,7 +3296,6 @@
3119
3296
  await diskWriter.ready;
3120
3297
  await diskWriter.write(chunk);
3121
3298
  diskSourceWriter.size += chunkLength;
3122
- writer.size += chunkLength;
3123
3299
  writer.availableSize -= chunkLength;
3124
3300
  }
3125
3301
  }
@@ -3219,7 +3395,7 @@
3219
3395
 
3220
3396
  /* global TextDecoder */
3221
3397
 
3222
- const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3398
+ const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3223
3399
  const VALID_CP437 = CP437.length == 256;
3224
3400
 
3225
3401
  function decodeCP437(stringValue) {
@@ -3267,7 +3443,8 @@
3267
3443
  if (encoding && encoding.trim().toLowerCase() == "cp437") {
3268
3444
  return decodeCP437(value);
3269
3445
  } else {
3270
- return new TextDecoder(encoding).decode(value);
3446
+ // ignoreBOM keeps a leading U+FEFF in filenames/comments instead of dropping it
3447
+ return new TextDecoder(encoding, { ignoreBOM: true }).decode(value);
3271
3448
  }
3272
3449
  }
3273
3450
 
@@ -3444,6 +3621,7 @@
3444
3621
  const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
3445
3622
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
3446
3623
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
3624
+ const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
3447
3625
  const OPTION_CHECK_SIGNATURE = "checkSignature";
3448
3626
  const OPTION_USE_WEB_WORKERS = "useWebWorkers";
3449
3627
  const OPTION_USE_COMPRESSION_STREAM = "useCompressionStream";
@@ -3501,12 +3679,16 @@
3501
3679
  const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
3502
3680
  const ERR_ENCRYPTED = "File contains encrypted entry";
3503
3681
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
3504
- const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
3682
+ const ERR_UNSUPPORTED_COMPRESSION$1 = "Compression method not supported";
3505
3683
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
3506
3684
  const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
3685
+ const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
3507
3686
  const CHARSET_UTF8 = "utf-8";
3508
3687
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
3509
3688
  const CHARSET_CP437 = "cp437";
3689
+ // bits of the general purpose flag that change how an entry is interpreted; the level bits (1-2) are excluded
3690
+ // because they are informative only
3691
+ const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
3510
3692
  const ZIP64_PROPERTIES = [
3511
3693
  [PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
3512
3694
  [PROPERTY_NAME_COMPRESSED_SIZE, MAX_32_BITS],
@@ -3531,7 +3713,7 @@
3531
3713
  reader: new GenericReader(reader),
3532
3714
  options,
3533
3715
  config: getConfiguration(),
3534
- readRanges: []
3716
+ readRanges: new Map()
3535
3717
  });
3536
3718
  }
3537
3719
 
@@ -3564,21 +3746,30 @@
3564
3746
  const commentOffset = endOfDirectoryInfo.offset;
3565
3747
  const commentLength = getUint16(endOfDirectoryView, 20);
3566
3748
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
3749
+ const checkAmbiguity = getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY);
3750
+ if (checkAmbiguity && appendedDataOffset != reader.size) {
3751
+ throwAmbiguousArchive("appended data");
3752
+ }
3567
3753
  let lastDiskNumber = getUint16(endOfDirectoryView, 4);
3568
3754
  const expectedLastDiskNumber = reader.lastDiskNumber || 0;
3569
3755
  let diskNumber = getUint16(endOfDirectoryView, 6);
3570
- let filesLength = getUint16(endOfDirectoryView, 8);
3756
+ let filesLength = getUint16(endOfDirectoryView, 10);
3571
3757
  let prependedDataLength = 0;
3572
- let startOffset = 0;
3758
+ let startOffset;
3759
+ let zip64EndOfDirectory;
3573
3760
  if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
3574
- const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH);
3761
+ const endOfDirectoryLocatorArray = endOfDirectoryInfo.offset >= ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH ?
3762
+ await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH) :
3763
+ new Uint8Array();
3575
3764
  const endOfDirectoryLocatorView = getDataView$1(endOfDirectoryLocatorArray);
3576
- if (getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3765
+ if (endOfDirectoryLocatorArray.length == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH &&
3766
+ getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3577
3767
  directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8);
3578
3768
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3579
3769
  let endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3580
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
3581
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3770
+ const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH - (reader.lastDiskOffset || 0);
3771
+ if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
3772
+ directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
3582
3773
  const originalDirectoryDataOffset = directoryDataOffset;
3583
3774
  directoryDataOffset = expectedDirectoryDataOffset;
3584
3775
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3587,24 +3778,36 @@
3587
3778
  endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3588
3779
  endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3589
3780
  }
3590
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3781
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3591
3782
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
3592
3783
  }
3784
+ zip64EndOfDirectory = true;
3593
3785
  if (lastDiskNumber == MAX_16_BITS) {
3594
3786
  lastDiskNumber = getUint32(endOfDirectoryView, 16);
3787
+ } else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
3788
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3595
3789
  }
3596
3790
  if (diskNumber == MAX_16_BITS) {
3597
3791
  diskNumber = getUint32(endOfDirectoryView, 20);
3792
+ } else if (checkAmbiguity && diskNumber != getUint32(endOfDirectoryView, 20)) {
3793
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3598
3794
  }
3599
3795
  if (filesLength == MAX_16_BITS) {
3600
3796
  filesLength = getBigUint64(endOfDirectoryView, 32);
3797
+ } else if (checkAmbiguity && filesLength != getBigUint64(endOfDirectoryView, 32)) {
3798
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3601
3799
  }
3602
3800
  if (directoryDataLength == MAX_32_BITS) {
3603
3801
  directoryDataLength = getBigUint64(endOfDirectoryView, 40);
3802
+ } else if (checkAmbiguity && directoryDataLength != getBigUint64(endOfDirectoryView, 40)) {
3803
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3604
3804
  }
3605
- directoryDataOffset -= directoryDataLength;
3805
+ directoryDataOffset = getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
3606
3806
  }
3607
3807
  }
3808
+ const declaredDirectoryDataLength = directoryDataLength;
3809
+ const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
3810
+ (zip64EndOfDirectory ? ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
3608
3811
  if (directoryDataOffset >= reader.size) {
3609
3812
  prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
3610
3813
  directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
@@ -3619,8 +3822,11 @@
3619
3822
  let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3620
3823
  let directoryView = getDataView$1(directoryArray);
3621
3824
  if (directoryDataLength) {
3622
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength;
3623
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3825
+ if (directoryArray.length < 4) {
3826
+ throw new Error(ERR_BAD_FORMAT);
3827
+ }
3828
+ const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength - (reader.lastDiskOffset || 0);
3829
+ if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
3624
3830
  const originalDirectoryDataOffset = directoryDataOffset;
3625
3831
  directoryDataOffset = expectedDirectoryDataOffset;
3626
3832
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3630,8 +3836,8 @@
3630
3836
  directoryView = getDataView$1(directoryArray);
3631
3837
  }
3632
3838
  }
3633
- const expectedDirectoryDataLength = endOfDirectoryInfo.offset - directoryDataOffset - (reader.lastDiskOffset || 0);
3634
- if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0) {
3839
+ const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset - (reader.lastDiskOffset || 0);
3840
+ if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
3635
3841
  directoryDataLength = expectedDirectoryDataLength;
3636
3842
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3637
3843
  directoryView = getDataView$1(directoryArray);
@@ -3639,16 +3845,19 @@
3639
3845
  if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
3640
3846
  throw new Error(ERR_BAD_FORMAT);
3641
3847
  }
3848
+ startOffset = directoryDataOffset;
3642
3849
  const filenameEncoding = getOptionValue$1(zipReader, options, OPTION_FILENAME_ENCODING);
3643
3850
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
3851
+ const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
3852
+ let duplicateFilename;
3644
3853
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
3645
3854
  const fileEntry = new ZipEntry$1(reader, config, zipReader.options);
3646
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3855
+ if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3647
3856
  throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
3648
3857
  }
3649
3858
  readCommonHeader(fileEntry, directoryView, offset + 6);
3650
3859
  const languageEncodingFlag = Boolean(fileEntry.bitFlag.languageEncodingFlag);
3651
- const filenameOffset = offset + 46;
3860
+ const filenameOffset = offset + CENTRAL_FILE_HEADER_LENGTH;
3652
3861
  const extraFieldOffset = filenameOffset + fileEntry.filenameLength;
3653
3862
  const commentOffset = extraFieldOffset + fileEntry.extraFieldLength;
3654
3863
  const versionMadeBy = getUint16(directoryView, offset + 4);
@@ -3669,7 +3878,7 @@
3669
3878
  directory: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_DIR_MASK),
3670
3879
  archive: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_ARCHIVE_MASK)
3671
3880
  };
3672
- const offsetFileEntry = getUint32(directoryView, offset + 42) + prependedDataLength;
3881
+ const offsetFileEntry = getUint32(directoryView, offset + 42);
3673
3882
  const decode = getOptionValue$1(zipReader, options, OPTION_DECODE_TEXT) || decodeText;
3674
3883
  const rawFilenameEncoding = filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437;
3675
3884
  const rawCommentEncoding = commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437;
@@ -3682,6 +3891,7 @@
3682
3891
  comment = decodeText(rawComment, rawCommentEncoding);
3683
3892
  }
3684
3893
  Object.assign(fileEntry, {
3894
+ index: indexFile,
3685
3895
  versionMadeBy,
3686
3896
  msDosCompatible,
3687
3897
  compressedSize: 0,
@@ -3701,8 +3911,15 @@
3701
3911
  filename,
3702
3912
  comment
3703
3913
  });
3704
- startOffset = Math.max(offsetFileEntry, startOffset);
3705
3914
  readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
3915
+ fileEntry.offset += prependedDataLength;
3916
+ startOffset = Math.min(fileEntry.offset, startOffset);
3917
+ if (checkAmbiguity) {
3918
+ if (filenames.has(fileEntry.filename)) {
3919
+ duplicateFilename = true;
3920
+ }
3921
+ filenames.add(fileEntry.filename);
3922
+ }
3706
3923
  const unixExternalUpper = (fileEntry.externalFileAttributes >> 16) & MAX_16_BITS;
3707
3924
  if (fileEntry.unixMode === UNDEFINED_VALUE && (unixExternalUpper & (FILE_ATTR_UNIX_DEFAULT_MASK | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_TYPE_DIR)) != 0) {
3708
3925
  fileEntry.unixMode = unixExternalUpper;
@@ -3723,7 +3940,7 @@
3723
3940
  internalFileAttribute: fileEntry.internalFileAttributes,
3724
3941
  externalFileAttribute: fileEntry.externalFileAttributes,
3725
3942
  executable,
3726
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
3943
+ directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (fileEntry.filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
3727
3944
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
3728
3945
  });
3729
3946
  const entry = new Entry(fileEntry);
@@ -3746,6 +3963,15 @@
3746
3963
  }
3747
3964
  yield entry;
3748
3965
  }
3966
+ if (checkAmbiguity && offset != declaredDirectoryDataLength) {
3967
+ throwAmbiguousArchive("trailing central directory data");
3968
+ }
3969
+ if (duplicateFilename) {
3970
+ throwAmbiguousArchive("duplicate filename");
3971
+ }
3972
+ if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > 0))) {
3973
+ throwAmbiguousArchive("prepended data");
3974
+ }
3749
3975
  const extractPrependedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
3750
3976
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
3751
3977
  if (extractPrependedData) {
@@ -3785,9 +4011,21 @@
3785
4011
  readable: (function () {
3786
4012
  const { readable, writable } = new TransformStream();
3787
4013
  if (value.getData) {
3788
- value.getData(writable);
4014
+ getData();
3789
4015
  return readable;
3790
4016
  }
4017
+
4018
+ async function getData() {
4019
+ try {
4020
+ await value.getData(writable);
4021
+ } catch (error) {
4022
+ try {
4023
+ await writable.abort(error);
4024
+ } catch {
4025
+ // ignored
4026
+ }
4027
+ }
4028
+ }
3791
4029
  })()
3792
4030
  };
3793
4031
  delete chunk.getData;
@@ -3812,6 +4050,7 @@
3812
4050
  const zipEntry = this;
3813
4051
  const {
3814
4052
  reader,
4053
+ index,
3815
4054
  offset,
3816
4055
  diskNumberStart,
3817
4056
  extraFieldAES,
@@ -3837,27 +4076,42 @@
3837
4076
  rawPassword = rawPassword && rawPassword.length && rawPassword;
3838
4077
  if (extraFieldAES) {
3839
4078
  if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
3840
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4079
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3841
4080
  }
3842
4081
  }
3843
4082
  if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64) && !passThrough) {
3844
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4083
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3845
4084
  }
3846
- if (getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
4085
+ if (dataArray.length < HEADER_SIZE || getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
3847
4086
  throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
3848
4087
  }
3849
4088
  readCommonHeader(localDirectory, dataView, 4);
3850
4089
  const {
3851
4090
  extraFieldLength,
3852
- filenameLength,
3853
- lastAccessDate,
3854
- creationDate
4091
+ filenameLength
3855
4092
  } = localDirectory;
3856
- localDirectory.rawExtraField = extraFieldLength ?
3857
- await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
3858
- new Uint8Array();
4093
+ const checkAmbiguity = getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY);
4094
+ let rawLocalFilename = new Uint8Array();
4095
+ if (checkAmbiguity && (filenameLength || extraFieldLength)) {
4096
+ const trailingDataArray = await readUint8Array(reader, offset + HEADER_SIZE, filenameLength + extraFieldLength, diskNumberStart);
4097
+ rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
4098
+ localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
4099
+ } else {
4100
+ localDirectory.rawExtraField = extraFieldLength ?
4101
+ await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
4102
+ new Uint8Array();
4103
+ }
3859
4104
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
3860
- Object.assign(fileEntry, { lastAccessDate, creationDate });
4105
+ if (checkAmbiguity) {
4106
+ checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
4107
+ }
4108
+ const { lastAccessDate, creationDate } = localDirectory;
4109
+ if (lastAccessDate) {
4110
+ fileEntry.lastAccessDate = lastAccessDate;
4111
+ }
4112
+ if (creationDate) {
4113
+ fileEntry.creationDate = creationDate;
4114
+ }
3861
4115
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
3862
4116
  const zipCrypto = encrypted && !extraFieldAES;
3863
4117
  if (!passThrough) {
@@ -3903,7 +4157,7 @@
3903
4157
  outputSize: passThrough ? compressedSize : uncompressedSize,
3904
4158
  signature,
3905
4159
  compressed: compressionMethod != 0 && !passThrough,
3906
- encrypted: zipEntry.encrypted && !passThrough,
4160
+ encrypted,
3907
4161
  useWebWorkers: getOptionValue$1(zipEntry, options, OPTION_USE_WEB_WORKERS),
3908
4162
  useCompressionStream,
3909
4163
  transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
@@ -3917,6 +4171,7 @@
3917
4171
  await detectOverlappingEntry({
3918
4172
  reader,
3919
4173
  fileEntry,
4174
+ index,
3920
4175
  offset,
3921
4176
  diskNumberStart,
3922
4177
  signature,
@@ -4019,7 +4274,7 @@
4019
4274
  directory.extraFieldUnicodeComment = extraFieldUnicodeComment;
4020
4275
  }
4021
4276
  const extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES);
4022
- if (extraFieldAES) {
4277
+ if (extraFieldAES && extraFieldAES.data.length >= 7) {
4023
4278
  readExtraFieldAES(extraFieldAES, directory, compressionMethod);
4024
4279
  directory.extraFieldAES = extraFieldAES;
4025
4280
  } else {
@@ -4056,19 +4311,23 @@
4056
4311
  directory.zip64 = true;
4057
4312
  const extraFieldView = getDataView$1(extraFieldZip64.data);
4058
4313
  const missingProperties = ZIP64_PROPERTIES.filter(([propertyName, max]) => directory[propertyName] == max);
4314
+ const requiredLength = missingProperties.reduce((length, [, max]) => length + ZIP64_EXTRACTION[max].bytes, 0);
4315
+ if (extraFieldZip64.data.length < requiredLength) {
4316
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4317
+ }
4059
4318
  for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
4060
4319
  const [propertyName, max] = missingProperties[indexMissingProperty];
4061
- if (directory[propertyName] == max) {
4062
- const extraction = ZIP64_EXTRACTION[max];
4063
- directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4064
- offset += extraction.bytes;
4065
- } else if (extraFieldZip64[propertyName]) {
4066
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4067
- }
4320
+ const extraction = ZIP64_EXTRACTION[max];
4321
+ directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4322
+ offset += extraction.bytes;
4068
4323
  }
4069
4324
  }
4070
4325
 
4071
4326
  function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) {
4327
+ if (extraFieldUnicode.data.length < 5) {
4328
+ extraFieldUnicode.valid = false;
4329
+ return;
4330
+ }
4072
4331
  const extraFieldView = getDataView$1(extraFieldUnicode.data);
4073
4332
  const crc32 = new Crc32();
4074
4333
  crc32.append(fileEntry[rawPropertyName]);
@@ -4141,32 +4400,30 @@
4141
4400
  function readExtraFieldUnix(extraField, directory, isInfoZip) {
4142
4401
  try {
4143
4402
  const view = getDataView$1(new Uint8Array(extraField.data));
4144
- let offset = 0;
4145
- const version = getUint8(view, offset++);
4146
- const uidSize = getUint8(view, offset++);
4147
- const uidBytes = extraField.data.subarray(offset, offset + uidSize);
4148
- offset += uidSize;
4149
- const uid = unpackUnixId(uidBytes);
4150
- const gidSize = getUint8(view, offset++);
4151
- const gidBytes = extraField.data.subarray(offset, offset + gidSize);
4152
- offset += gidSize;
4153
- const gid = unpackUnixId(gidBytes);
4154
- let unixMode = UNDEFINED_VALUE;
4155
- if (!isInfoZip && offset + 2 <= extraField.data.length) {
4156
- const base = extraField.data;
4157
- const modeView = new DataView(base.buffer, base.byteOffset + offset, 2);
4158
- unixMode = modeView.getUint16(0, true);
4159
- }
4160
- Object.assign(extraField, { version, uid, gid, unixMode });
4403
+ let uid, gid;
4404
+ if (isInfoZip) {
4405
+ // Info-ZIP New Unix "ux" field (0x7875): version + variable-length uid/gid
4406
+ let offset = 0;
4407
+ const version = getUint8(view, offset++);
4408
+ const uidSize = getUint8(view, offset++);
4409
+ uid = unpackUnixId(extraField.data.subarray(offset, offset + uidSize));
4410
+ offset += uidSize;
4411
+ const gidSize = getUint8(view, offset++);
4412
+ gid = unpackUnixId(extraField.data.subarray(offset, offset + gidSize));
4413
+ Object.assign(extraField, { version, uid, gid });
4414
+ } else if (extraField.data.length >= 4) {
4415
+ // Info-ZIP Unix "Ux" field (0x7855): fixed 2-byte uid + gid (the file mode, if any, is
4416
+ // carried in the external file attributes, not here)
4417
+ uid = getUint16(view, 0);
4418
+ gid = getUint16(view, 2);
4419
+ Object.assign(extraField, { uid, gid });
4420
+ }
4161
4421
  if (uid !== UNDEFINED_VALUE) {
4162
4422
  directory.uid = uid;
4163
4423
  }
4164
4424
  if (gid !== UNDEFINED_VALUE) {
4165
4425
  directory.gid = gid;
4166
4426
  }
4167
- if (unixMode !== UNDEFINED_VALUE) {
4168
- directory.unixMode = unixMode;
4169
- }
4170
4427
  } catch {
4171
4428
  // ignored
4172
4429
  }
@@ -4180,6 +4437,9 @@
4180
4437
  }
4181
4438
 
4182
4439
  function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory) {
4440
+ if (!extraFieldExtendedTimestamp.data.length) {
4441
+ return;
4442
+ }
4183
4443
  const extraFieldView = getDataView$1(extraFieldExtendedTimestamp.data);
4184
4444
  const flags = getUint8(extraFieldView, 0);
4185
4445
  const timeProperties = [];
@@ -4205,7 +4465,8 @@
4205
4465
  timeProperties.forEach((propertyName, indexProperty) => {
4206
4466
  if (extraFieldExtendedTimestamp.data.length >= offset + 4) {
4207
4467
  const time = getUint32(extraFieldView, offset);
4208
- directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date(time * 1000);
4468
+ // the extended timestamp is a signed 32-bit time_t value
4469
+ directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date((time | 0) * 1000);
4209
4470
  const rawPropertyName = timeRawProperties[indexProperty];
4210
4471
  extraFieldExtendedTimestamp[rawPropertyName] = time;
4211
4472
  }
@@ -4216,6 +4477,7 @@
4216
4477
  async function detectOverlappingEntry({
4217
4478
  reader,
4218
4479
  fileEntry,
4480
+ index,
4219
4481
  offset,
4220
4482
  diskNumberStart,
4221
4483
  signature,
@@ -4227,10 +4489,9 @@
4227
4489
  readRanges
4228
4490
  }) {
4229
4491
  let diskOffset = 0;
4230
- if (diskNumberStart) {
4231
- for (let indexReader = 0; indexReader < diskNumberStart; indexReader++) {
4232
- const diskReader = reader.readers[indexReader];
4233
- diskOffset += diskReader.size;
4492
+ if (diskNumberStart && reader.readers) {
4493
+ for (let indexReader = 0; indexReader < Math.min(diskNumberStart, reader.readers.length); indexReader++) {
4494
+ diskOffset += reader.readers[indexReader].size;
4234
4495
  }
4235
4496
  }
4236
4497
  let dataDescriptorLength = 0;
@@ -4243,7 +4504,8 @@
4243
4504
  }
4244
4505
  if (dataDescriptorLength) {
4245
4506
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, diskNumberStart);
4246
- const dataDescriptorSignature = getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4507
+ const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
4508
+ getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4247
4509
  if (dataDescriptorSignature) {
4248
4510
  const readSignature = getUint32(getDataView$1(dataDescriptorArray), 4);
4249
4511
  let readCompressedSize;
@@ -4268,14 +4530,14 @@
4268
4530
  end: diskOffset + dataOffset + compressedSize + dataDescriptorLength,
4269
4531
  fileEntry
4270
4532
  };
4271
- for (const otherRange of readRanges) {
4272
- if (otherRange.fileEntry != fileEntry && range.start >= otherRange.start && range.start < otherRange.end) {
4533
+ for (const [otherIndex, otherRange] of readRanges) {
4534
+ if (otherIndex != index && range.start < otherRange.end && otherRange.start < range.end) {
4273
4535
  const error = new Error(ERR_OVERLAPPING_ENTRY);
4274
4536
  error.overlappingEntry = otherRange.fileEntry;
4275
4537
  throw error;
4276
4538
  }
4277
4539
  }
4278
- readRanges.push(range);
4540
+ readRanges.set(index, range);
4279
4541
  }
4280
4542
 
4281
4543
  async function seekSignature(reader, signature, startOffset, minimumBytes, maximumLength) {
@@ -4300,6 +4562,35 @@
4300
4562
  }
4301
4563
  }
4302
4564
 
4565
+ function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
4566
+ const { rawFilename } = zipEntry;
4567
+ if (rawLocalFilename.length != rawFilename.length ||
4568
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
4569
+ throwAmbiguousArchive("mismatched local file header (filename)");
4570
+ }
4571
+ if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
4572
+ throwAmbiguousArchive("mismatched local file header (general purpose bit flag)");
4573
+ }
4574
+ if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
4575
+ throwAmbiguousArchive("mismatched local file header (compression method)");
4576
+ }
4577
+ // when the data descriptor flag is set, the local signature and sizes are zeroed out; all-zero values are
4578
+ // also tolerated when the flag is clear because some tools produce them (streaming writers predating bit 3)
4579
+ if (!localDirectory.bitFlag.dataDescriptor &&
4580
+ (localDirectory.signature || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
4581
+ (localDirectory.signature != zipEntry.signature ||
4582
+ localDirectory.compressedSize != zipEntry.compressedSize ||
4583
+ localDirectory.uncompressedSize != zipEntry.uncompressedSize)) {
4584
+ throwAmbiguousArchive("mismatched local file header (signature or sizes)");
4585
+ }
4586
+ }
4587
+
4588
+ function throwAmbiguousArchive(reason) {
4589
+ const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
4590
+ error.reason = reason;
4591
+ throw error;
4592
+ }
4593
+
4303
4594
  function getOptionValue$1(zipReader, options, name) {
4304
4595
  return options[name] === UNDEFINED_VALUE ? zipReader.options[name] : options[name];
4305
4596
  }
@@ -4338,7 +4629,7 @@
4338
4629
  }
4339
4630
 
4340
4631
  function getDataView$1(array) {
4341
- return new DataView(array.buffer);
4632
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
4342
4633
  }
4343
4634
 
4344
4635
  /*
@@ -4378,13 +4669,19 @@
4378
4669
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
4379
4670
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
4380
4671
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
4672
+ // same message as the constant exported by zip-reader.js
4673
+ const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
4674
+ const MIN_UNIX_TIME = -2147483648;
4675
+ const MAX_UNIX_TIME = 2147483647;
4381
4676
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
4382
4677
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
4678
+ const ERR_UNDEFINED_READER = "Undefined reader";
4383
4679
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
4384
4680
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
4385
4681
  const ERR_INVALID_GID = "Invalid gid (must be integer 0..2^32-1)";
4386
4682
  const ERR_INVALID_UNIX_MODE = "Invalid UNIX mode (must be integer 0..65535)";
4387
4683
  const ERR_INVALID_UNIX_EXTRA_FIELD_TYPE = "Invalid unixExtraFieldType (must be 'infozip' or 'unix')";
4684
+ const ERR_INVALID_UNIX_ID_SIZE = "uid/gid must be 0..65535 for unixExtraFieldType 'unix' (use 'infozip' for larger ids)";
4388
4685
  const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be integer 0..255)";
4389
4686
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
4390
4687
 
@@ -4410,9 +4707,10 @@
4410
4707
  files: new Map(),
4411
4708
  filenames: new Set(),
4412
4709
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
4413
- pendingEntriesSize: 0,
4710
+ initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
4414
4711
  pendingAddFileCalls: new Set(),
4415
- bufferedWrites: 0
4712
+ bufferedWrites: 0,
4713
+ lastFileEntry: UNDEFINED_VALUE
4416
4714
  });
4417
4715
  }
4418
4716
 
@@ -4421,17 +4719,18 @@
4421
4719
  throw new Error(ERR_ZIP_NOT_EMPTY);
4422
4720
  }
4423
4721
  reader = new GenericReader(reader);
4722
+ await initStream(reader);
4424
4723
  const zipReader = new ZipReader(reader.readable);
4425
4724
  const entries = await zipReader.getEntries();
4426
4725
  await zipReader.close();
4726
+ await initStream(this.writer);
4427
4727
  await reader.readable.pipeTo(this.writer.writable, { preventClose: true, preventAbort: true });
4428
4728
  this.writer.size = this.offset = reader.size;
4429
4729
  this.filenames = new Set(entries.map(entry => entry.filename));
4430
4730
  this.files = new Map(entries.map(entry => {
4431
4731
  const {
4432
4732
  version,
4433
- compressionMethod,
4434
- lastModDate,
4733
+ rawLastModDate,
4435
4734
  lastAccessDate,
4436
4735
  creationDate,
4437
4736
  rawFilename,
@@ -4444,6 +4743,7 @@
4444
4743
  zip64
4445
4744
  } = entry;
4446
4745
  let {
4746
+ compressionMethod,
4447
4747
  rawExtraFieldZip64,
4448
4748
  rawExtraFieldAES,
4449
4749
  rawExtraFieldExtendedTimestamp,
@@ -4456,31 +4756,39 @@
4456
4756
  rawExtraFieldAES = rawExtraFieldAES || new Uint8Array();
4457
4757
  rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || new Uint8Array();
4458
4758
  rawExtraFieldNTFS = rawExtraFieldNTFS || new Uint8Array();
4459
- rawExtraFieldUnix = entry.rawExtraFieldUnix || new Uint8Array();
4759
+ rawExtraFieldUnix = rawExtraFieldUnix || new Uint8Array();
4460
4760
  rawExtraField = rawExtraField || new Uint8Array();
4761
+ if (entry.extraFieldAES) {
4762
+ compressionMethod = COMPRESSION_METHOD_AES;
4763
+ }
4461
4764
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
4462
- const zip64UncompressedSize = zip64 && uncompressedSize > MAX_32_BITS;
4463
- const zip64CompressedSize = zip64 && compressedSize > MAX_32_BITS;
4765
+ const zip64UncompressedSize = zip64 && uncompressedSize >= MAX_32_BITS;
4766
+ const zip64CompressedSize = zip64 && compressedSize >= MAX_32_BITS;
4767
+ const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
4464
4768
  const {
4465
4769
  headerArray,
4466
4770
  headerView
4467
4771
  } = getHeaderArrayData({
4468
4772
  version,
4469
- bitFlag: getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod),
4773
+ bitFlag: bitFlagValue,
4470
4774
  compressionMethod,
4471
4775
  uncompressedSize,
4472
4776
  compressedSize,
4473
- lastModDate,
4777
+ rawLastModDate,
4474
4778
  rawFilename,
4475
4779
  zip64CompressedSize,
4476
4780
  zip64UncompressedSize,
4477
4781
  extraFieldLength
4478
4782
  });
4783
+ const { signature } = entry;
4784
+ if (signature !== UNDEFINED_VALUE) {
4785
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, signature);
4786
+ }
4479
4787
  Object.assign(entry, {
4480
4788
  zip64UncompressedSize,
4481
4789
  zip64CompressedSize,
4482
- zip64Offset: zip64 && this.offset - diskOffset > MAX_32_BITS,
4483
- zip64DiskNumberStart: zip64 && diskNumber > MAX_16_BITS,
4790
+ zip64Offset: zip64 && this.offset - diskOffset >= MAX_32_BITS,
4791
+ zip64DiskNumberStart: zip64 && diskNumber >= MAX_16_BITS,
4484
4792
  rawExtraFieldZip64,
4485
4793
  rawExtraFieldAES,
4486
4794
  rawExtraFieldExtendedTimestamp,
@@ -4498,6 +4806,7 @@
4498
4806
 
4499
4807
  async add(name = "", reader, options = {}) {
4500
4808
  const zipWriter = this;
4809
+ options = Object.assign({}, options);
4501
4810
  const {
4502
4811
  pendingAddFileCalls,
4503
4812
  config
@@ -4508,17 +4817,24 @@
4508
4817
  await new Promise(resolve => pendingEntries.push(resolve));
4509
4818
  }
4510
4819
  let promiseAddFile;
4820
+ let nameAdded;
4511
4821
  try {
4512
4822
  name = name.trim();
4823
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
4824
+ name += DIRECTORY_SIGNATURE;
4825
+ }
4513
4826
  if (zipWriter.filenames.has(name)) {
4514
4827
  throw new Error(ERR_DUPLICATED_NAME);
4515
4828
  }
4516
4829
  zipWriter.filenames.add(name);
4830
+ nameAdded = true;
4517
4831
  promiseAddFile = addFile(zipWriter, name, reader, options);
4518
4832
  pendingAddFileCalls.add(promiseAddFile);
4519
4833
  return await promiseAddFile;
4520
4834
  } catch (error) {
4521
- zipWriter.filenames.delete(name);
4835
+ if (nameAdded) {
4836
+ zipWriter.filenames.delete(name);
4837
+ }
4522
4838
  throw error;
4523
4839
  } finally {
4524
4840
  pendingAddFileCalls.delete(promiseAddFile);
@@ -4551,6 +4867,9 @@
4551
4867
  const zipWriter = this;
4552
4868
  const { pendingAddFileCalls, writer } = this;
4553
4869
  const { writable } = writer;
4870
+ if (getLength(comment) > MAX_16_BITS) {
4871
+ throw new Error(ERR_INVALID_COMMENT);
4872
+ }
4554
4873
  while (pendingAddFileCalls.size) {
4555
4874
  await Promise.allSettled(Array.from(pendingAddFileCalls));
4556
4875
  }
@@ -4569,28 +4888,94 @@
4569
4888
  const { readable, writable } = new TransformStream();
4570
4889
  this.readable = readable;
4571
4890
  this.zipWriter = new ZipWriter(writable, options);
4891
+ this.pendingAddFileCalls = new Set();
4572
4892
  }
4573
4893
 
4574
4894
  transform(path) {
4895
+ const zipWriter = this.zipWriter;
4896
+ let streamController;
4575
4897
  const { readable, writable } = new TransformStream({
4576
- flush: () => { this.zipWriter.close(); }
4898
+ start(controller) {
4899
+ streamController = controller;
4900
+ },
4901
+ flush: () => void closeArchive()
4577
4902
  });
4578
- this.zipWriter.add(path, readable);
4903
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4579
4904
  return { readable: this.readable, writable };
4905
+
4906
+ async function closeArchive() {
4907
+ try {
4908
+ await zipWriter.close();
4909
+ } catch (error) {
4910
+ try {
4911
+ await zipWriter.writer.writable.abort(error);
4912
+ } catch {
4913
+ // ignored
4914
+ }
4915
+ }
4916
+ }
4580
4917
  }
4581
4918
 
4582
4919
  writable(path) {
4583
- const { readable, writable } = new TransformStream();
4584
- this.zipWriter.add(path, readable);
4920
+ let streamController;
4921
+ const { readable, writable } = new TransformStream({
4922
+ start(controller) {
4923
+ streamController = controller;
4924
+ }
4925
+ });
4926
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4585
4927
  return writable;
4586
4928
  }
4587
4929
 
4588
- close(comment = UNDEFINED_VALUE, options = {}) {
4930
+ async close(comment = UNDEFINED_VALUE, options = {}) {
4931
+ await Promise.all(Array.from(this.pendingAddFileCalls));
4589
4932
  return this.zipWriter.close(comment, options);
4590
4933
  }
4591
4934
  }
4592
4935
 
4936
+ function watchAddFileCall(zipWriterStream, promiseAddFile, onerror) {
4937
+ zipWriterStream.pendingAddFileCalls.add(promiseAddFile);
4938
+ promiseAddFile.catch(error => {
4939
+ try {
4940
+ onerror(error);
4941
+ } catch {
4942
+ // ignored
4943
+ }
4944
+ });
4945
+ }
4946
+
4593
4947
  async function addFile(zipWriter, name, reader, options) {
4948
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
4949
+ ({ name } = attributesInfo);
4950
+ const metadataInfo = resolveMetadata(zipWriter, name, options);
4951
+ const { comment } = metadataInfo;
4952
+ const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
4953
+ zipWriter.files.set(name, UNDEFINED_VALUE);
4954
+ let fileEntry;
4955
+ try {
4956
+ const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
4957
+ ({ reader } = sizesInfo);
4958
+ const { diskOffset, diskNumber } = zipWriter.writer;
4959
+ options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
4960
+ internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
4961
+ externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
4962
+ signature: options[PROPERTY_NAME_SIGNATURE],
4963
+ offset: zipWriter.offset - diskOffset,
4964
+ diskNumberStart: diskNumber
4965
+ });
4966
+ const headerInfo = getHeaderInfo(options);
4967
+ const dataDescriptorInfo = getDataDescriptorInfo(options);
4968
+ const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
4969
+ fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
4970
+ } catch (error) {
4971
+ zipWriter.files.delete(name);
4972
+ throw error;
4973
+ }
4974
+ Object.assign(fileEntry, { name, comment, extraField });
4975
+ return new Entry(fileEntry);
4976
+ }
4977
+
4978
+ function resolveAttributes(zipWriter, name, options) {
4594
4979
  name = name.trim();
4595
4980
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
4596
4981
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
@@ -4598,7 +4983,7 @@
4598
4983
  const uid = getOptionValue(zipWriter, options, PROPERTY_NAME_UID);
4599
4984
  const gid = getOptionValue(zipWriter, options, PROPERTY_NAME_GID);
4600
4985
  let unixMode = getOptionValue(zipWriter, options, PROPERTY_NAME_UNIX_MODE);
4601
- const unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
4986
+ let unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
4602
4987
  let setuid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETUID);
4603
4988
  let setgid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETGID);
4604
4989
  let sticky = getOptionValue(zipWriter, options, PROPERTY_NAME_STICKY);
@@ -4614,6 +4999,13 @@
4614
4999
  if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
4615
5000
  throw new Error(ERR_INVALID_UNIX_EXTRA_FIELD_TYPE);
4616
5001
  }
5002
+ if (unixExtraFieldType === UNIX_EXTRA_FIELD_TYPE &&
5003
+ ((uid !== UNDEFINED_VALUE && uid > MAX_16_BITS) || (gid !== UNDEFINED_VALUE && gid > MAX_16_BITS))) {
5004
+ throw new Error(ERR_INVALID_UNIX_ID_SIZE);
5005
+ }
5006
+ if (unixExtraFieldType === UNDEFINED_VALUE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5007
+ unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE;
5008
+ }
4617
5009
  let msdosAttributesRaw = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW);
4618
5010
  let msdosAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES);
4619
5011
  const hasUnixMetadata = uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE || unixExtraFieldType;
@@ -4684,6 +5076,27 @@
4684
5076
  if (hasMsDosProvided) {
4685
5077
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
4686
5078
  }
5079
+ return {
5080
+ name,
5081
+ resolvedOptions: {
5082
+ versionMadeBy,
5083
+ msDosCompatible,
5084
+ externalFileAttributes,
5085
+ unixExternalUpper,
5086
+ uid,
5087
+ gid,
5088
+ unixMode,
5089
+ unixExtraFieldType,
5090
+ setuid,
5091
+ setgid,
5092
+ sticky,
5093
+ msdosAttributesRaw,
5094
+ msdosAttributes
5095
+ }
5096
+ };
5097
+ }
5098
+
5099
+ function resolveMetadata(zipWriter, name, options) {
4687
5100
  const encode = getOptionValue(zipWriter, options, OPTION_ENCODE_TEXT, encodeText);
4688
5101
  let rawFilename = encode(name);
4689
5102
  if (rawFilename === UNDEFINED_VALUE) {
@@ -4722,10 +5135,14 @@
4722
5135
  const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS, true);
4723
5136
  const bufferedWrite = getOptionValue(zipWriter, options, OPTION_BUFFERED_WRITE);
4724
5137
  const createTempStream = getOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
4725
- const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, false);
5138
+ const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
4726
5139
  const signal = getOptionValue(zipWriter, options, OPTION_SIGNAL);
4727
5140
  const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
4728
5141
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
5142
+ if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
5143
+ compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE) {
5144
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5145
+ }
4729
5146
  let level = getOptionValue(zipWriter, options, OPTION_LEVEL);
4730
5147
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
4731
5148
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
@@ -4741,7 +5158,7 @@
4741
5158
  if (!useCompressionStream && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
4742
5159
  level = 0;
4743
5160
  }
4744
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5161
+ const zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
4745
5162
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
4746
5163
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
4747
5164
  }
@@ -4752,6 +5169,7 @@
4752
5169
  let offset = 0;
4753
5170
  extraField.forEach(data => extraFieldSize += 4 + getLength(data));
4754
5171
  rawExtraField = new Uint8Array(extraFieldSize);
5172
+ const rawExtraFieldView = getDataView(rawExtraField);
4755
5173
  extraField.forEach((data, type) => {
4756
5174
  if (type > MAX_16_BITS) {
4757
5175
  throw new Error(ERR_INVALID_EXTRAFIELD_TYPE);
@@ -4759,22 +5177,72 @@
4759
5177
  if (getLength(data) > MAX_16_BITS) {
4760
5178
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
4761
5179
  }
4762
- arraySet(rawExtraField, new Uint16Array([type]), offset);
4763
- arraySet(rawExtraField, new Uint16Array([getLength(data)]), offset + 2);
5180
+ setUint16(rawExtraFieldView, offset, type);
5181
+ setUint16(rawExtraFieldView, offset + 2, getLength(data));
4764
5182
  arraySet(rawExtraField, data, offset + 4);
4765
5183
  offset += 4 + getLength(data);
4766
5184
  });
4767
5185
  }
5186
+ return {
5187
+ comment,
5188
+ resolvedOptions: {
5189
+ rawFilename,
5190
+ rawComment,
5191
+ version,
5192
+ lastModDate,
5193
+ lastAccessDate,
5194
+ creationDate,
5195
+ internalFileAttributes,
5196
+ passThrough,
5197
+ password,
5198
+ rawPassword,
5199
+ encryptionStrength,
5200
+ zipCrypto,
5201
+ extendedTimestamp,
5202
+ keepOrder,
5203
+ useWebWorkers,
5204
+ transferStreams,
5205
+ bufferedWrite,
5206
+ createTempStream,
5207
+ dataDescriptorSignature,
5208
+ signal,
5209
+ useUnicodeFileNames,
5210
+ compressionMethod,
5211
+ level,
5212
+ useCompressionStream,
5213
+ dataDescriptor,
5214
+ zip64,
5215
+ rawExtraField
5216
+ }
5217
+ };
5218
+ }
5219
+
5220
+ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
5221
+ const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
5222
+ let { dataDescriptor, zip64, level, compressionMethod } = metadata;
4768
5223
  let maximumCompressedSize = 0;
4769
- let maximumEntrySize = 0;
4770
5224
  let uncompressedSize = 0;
4771
5225
  if (passThrough) {
5226
+ // the headers of a passThrough entry describe the payload verbatim: without a
5227
+ // reader they would declare content that is not there
5228
+ if (!reader) {
5229
+ throw new Error(ERR_UNDEFINED_READER);
5230
+ }
4772
5231
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
4773
5232
  if (uncompressedSize === UNDEFINED_VALUE) {
4774
5233
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
4775
5234
  }
4776
5235
  }
4777
5236
  const zip64Enabled = zip64 === true;
5237
+ const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
5238
+ // entries without a reader have no payload: write them as empty stored files instead of
5239
+ // declaring a compressed or encrypted content that does not exist
5240
+ const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
5241
+ if (!reader) {
5242
+ level = 0;
5243
+ compressionMethod = COMPRESSION_METHOD_STORE;
5244
+ }
5245
+ const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4778
5246
  if (reader) {
4779
5247
  reader = new GenericReader(reader);
4780
5248
  await initStream(reader);
@@ -4787,16 +5255,15 @@
4787
5255
  }
4788
5256
  } else {
4789
5257
  options.uncompressedSize = uncompressedSize = reader.size;
4790
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5258
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4791
5259
  }
4792
5260
  } else {
4793
5261
  options.uncompressedSize = uncompressedSize;
4794
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5262
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4795
5263
  }
4796
5264
  }
4797
- const { diskOffset, diskNumber } = zipWriter.writer;
4798
- const zip64UncompressedSize = zip64Enabled || uncompressedSize > MAX_32_BITS;
4799
- const zip64CompressedSize = zip64Enabled || maximumCompressedSize > MAX_32_BITS;
5265
+ const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
5266
+ const zip64CompressedSize = zip64Enabled || maximumCompressedSize >= MAX_32_BITS;
4800
5267
  if (zip64UncompressedSize || zip64CompressedSize) {
4801
5268
  if (zip64 === false) {
4802
5269
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -4805,73 +5272,19 @@
4805
5272
  }
4806
5273
  }
4807
5274
  zip64 = zip64 || false;
4808
- const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
4809
- options = Object.assign({}, options, {
4810
- rawFilename,
4811
- rawComment,
4812
- version,
4813
- versionMadeBy,
4814
- lastModDate,
4815
- lastAccessDate,
4816
- creationDate,
4817
- rawExtraField,
4818
- zip64,
4819
- zip64UncompressedSize,
4820
- zip64CompressedSize,
4821
- password,
4822
- rawPassword,
4823
- level,
4824
- useWebWorkers,
4825
- transferStreams,
4826
- encryptionStrength,
4827
- extendedTimestamp,
4828
- zipCrypto,
4829
- bufferedWrite,
4830
- createTempStream,
4831
- keepOrder,
4832
- useUnicodeFileNames,
4833
- dataDescriptor,
4834
- dataDescriptorSignature,
4835
- signal,
4836
- msDosCompatible,
4837
- internalFileAttribute: internalFileAttributes,
4838
- internalFileAttributes,
4839
- externalFileAttribute: externalFileAttributes,
4840
- externalFileAttributes,
4841
- useCompressionStream,
4842
- passThrough,
4843
- encrypted: Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted),
4844
- signature: options[PROPERTY_NAME_SIGNATURE],
4845
- compressionMethod,
4846
- uncompressedSize,
4847
- offset: zipWriter.offset - diskOffset,
4848
- diskNumberStart: diskNumber,
4849
- uid,
4850
- gid,
4851
- setuid,
4852
- setgid,
4853
- sticky,
4854
- unixMode,
4855
- msdosAttributesRaw,
4856
- msdosAttributes,
4857
- unixExternalUpper
4858
- });
4859
- const headerInfo = getHeaderInfo(options);
4860
- const dataDescriptorInfo = getDataDescriptorInfo(options);
4861
- const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
4862
- maximumEntrySize = metadataSize + maximumCompressedSize;
4863
- if (zipWriter.options[OPTION_USDZ]) {
4864
- maximumEntrySize += maximumEntrySize + 64;
4865
- }
4866
- zipWriter.pendingEntriesSize += maximumEntrySize;
4867
- let fileEntry;
4868
- try {
4869
- fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
4870
- } finally {
4871
- zipWriter.pendingEntriesSize -= maximumEntrySize;
4872
- }
4873
- Object.assign(fileEntry, { name, comment, extraField });
4874
- return new Entry(fileEntry);
5275
+ return {
5276
+ reader,
5277
+ resolvedOptions: {
5278
+ dataDescriptor,
5279
+ zip64,
5280
+ zip64UncompressedSize,
5281
+ zip64CompressedSize,
5282
+ uncompressedSize,
5283
+ level,
5284
+ compressionMethod,
5285
+ encrypted: encryptedEntry
5286
+ }
5287
+ };
4875
5288
  }
4876
5289
 
4877
5290
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
@@ -4888,37 +5301,40 @@
4888
5301
  headerInfo
4889
5302
  } = entryInfo;
4890
5303
  const usdz = zipWriter.options[OPTION_USDZ];
4891
- const previousFileEntry = Array.from(files.values()).pop();
5304
+ const previousFileEntry = zipWriter.lastFileEntry;
4892
5305
  let fileEntry = {};
4893
5306
  let bufferedWrite;
4894
5307
  let releaseLockWriter;
4895
5308
  let releaseLockCurrentFileEntry;
4896
5309
  let writingBufferedEntryData;
4897
5310
  let writingEntryData;
5311
+ let writerSizeBeforeEntry;
5312
+ let flushedBufferedSize = 0;
4898
5313
  let fileWriter;
4899
5314
  files.set(name, fileEntry);
5315
+ zipWriter.lastFileEntry = fileEntry;
4900
5316
  try {
4901
5317
  let lockPreviousFileEntry;
4902
5318
  if (keepOrder) {
4903
5319
  lockPreviousFileEntry = previousFileEntry && previousFileEntry.lock;
4904
5320
  requestLockCurrentFileEntry();
4905
5321
  }
4906
- if ((options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) && !usdz) {
5322
+ if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) {
5323
+ bufferedWrite = true;
5324
+ zipWriter.bufferedWrites++;
4907
5325
  if (options.createTempStream) {
4908
5326
  fileWriter = await options.createTempStream();
4909
5327
  } else {
4910
5328
  fileWriter = new TransformStream(UNDEFINED_VALUE, UNDEFINED_VALUE, { highWaterMark: INFINITY_VALUE });
4911
5329
  }
4912
5330
  fileWriter.size = 0;
4913
- bufferedWrite = true;
4914
- zipWriter.bufferedWrites++;
4915
5331
  await initStream(writer);
4916
5332
  } else {
4917
5333
  fileWriter = writer;
4918
5334
  await requestLockWriter();
4919
5335
  }
4920
5336
  await initStream(fileWriter);
4921
- const { writable, diskOffset } = writer;
5337
+ const { diskOffset } = writer;
4922
5338
  if (zipWriter.addSplitZipSignature) {
4923
5339
  delete zipWriter.addSplitZipSignature;
4924
5340
  const signatureArray = new Uint8Array(4);
@@ -4927,21 +5343,20 @@
4927
5343
  await writeData(writer, signatureArray);
4928
5344
  zipWriter.offset += 4;
4929
5345
  }
4930
- if (usdz) {
5346
+ if (usdz && !bufferedWrite) {
4931
5347
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
4932
5348
  }
4933
- const {
4934
- localHeaderView,
4935
- localHeaderArray
4936
- } = headerInfo;
5349
+ const { localHeaderArray } = headerInfo;
4937
5350
  if (!bufferedWrite) {
4938
5351
  await lockPreviousFileEntry;
4939
- await skipDiskIfNeeded(writable);
5352
+ await skipDiskIfNeeded();
4940
5353
  }
4941
- const { diskNumber } = writer;
4942
- fileEntry.diskNumberStart = diskNumber;
5354
+ const diskNumberStart = writer.diskNumber;
5355
+ const entryOffset = getSegmentOffset(zipWriter, writer);
5356
+ fileEntry.diskNumberStart = diskNumberStart;
4943
5357
  if (!bufferedWrite) {
4944
5358
  writingEntryData = true;
5359
+ writerSizeBeforeEntry = writer.size;
4945
5360
  await writeData(fileWriter, localHeaderArray);
4946
5361
  }
4947
5362
  fileEntry = await createFileEntry(reader, fileWriter, fileEntry, entryInfo, zipWriter.config, options);
@@ -4954,16 +5369,24 @@
4954
5369
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
4955
5370
  await requestLockWriter();
4956
5371
  writingBufferedEntryData = true;
5372
+ writerSizeBeforeEntry = writer.size;
5373
+ await skipDiskIfNeeded();
4957
5374
  fileEntry.diskNumberStart = writer.diskNumber;
4958
- fileEntry.offset = zipWriter.offset - writer.diskOffset;
4959
- updateLocalHeader(fileEntry, localHeaderView, options);
4960
- await skipDiskIfNeeded(writable);
4961
- await writeData(writer, localHeaderArray);
4962
- await fileWriter.readable.pipeTo(writable, { preventClose: true, preventAbort: true, signal });
5375
+ fileEntry.offset = getSegmentOffset(zipWriter, writer);
5376
+ if (usdz) {
5377
+ // the padding depends on the entry offset, only known now that the writer is locked
5378
+ const previousMetadataSize = entryInfo.metadataSize;
5379
+ appendExtraFieldUSDZ(entryInfo, zipWriter.offset - writer.diskOffset);
5380
+ fileEntry.size += entryInfo.metadataSize - previousMetadataSize;
5381
+ }
5382
+ updateLocalHeader(fileEntry, headerInfo.localHeaderView, options);
5383
+ await writeData(writer, headerInfo.localHeaderArray);
5384
+ await flushBufferedData(fileWriter.readable, writer, signal, chunkLength => flushedBufferedSize += chunkLength);
4963
5385
  writer.size += fileWriter.size;
4964
5386
  writingBufferedEntryData = false;
4965
5387
  } else {
4966
- fileEntry.offset = zipWriter.offset - diskOffset;
5388
+ fileEntry.diskNumberStart = diskNumberStart;
5389
+ fileEntry.offset = entryOffset;
4967
5390
  }
4968
5391
  zipWriter.offset += fileEntry.size;
4969
5392
  return fileEntry;
@@ -4977,10 +5400,9 @@
4977
5400
  // ignored
4978
5401
  }
4979
5402
  }
5403
+ zipWriter.offset += writer.size - writerSizeBeforeEntry;
4980
5404
  if (bufferedWrite) {
4981
- zipWriter.offset += fileWriter.size;
4982
- } else {
4983
- zipWriter.offset = fileWriter.size;
5405
+ zipWriter.offset += flushedBufferedSize;
4984
5406
  }
4985
5407
  }
4986
5408
  files.delete(name);
@@ -5011,10 +5433,10 @@
5011
5433
  await lockWriter;
5012
5434
  }
5013
5435
 
5014
- async function skipDiskIfNeeded(writable) {
5436
+ async function skipDiskIfNeeded() {
5015
5437
  if (getLength(headerInfo.localHeaderArray) > writer.availableSize) {
5016
5438
  writer.availableSize = 0;
5017
- await writeData(writable, new Uint8Array());
5439
+ await writeData(writer, new Uint8Array());
5018
5440
  }
5019
5441
  }
5020
5442
  }
@@ -5155,6 +5577,10 @@
5155
5577
  uncompressedSize = result.inputSize;
5156
5578
  signature = result.signature;
5157
5579
  }
5580
+ if ((!zip64CompressedSize && compressedSize >= MAX_32_BITS) ||
5581
+ (!zip64UncompressedSize && uncompressedSize >= MAX_32_BITS)) {
5582
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
5583
+ }
5158
5584
  } catch (error) {
5159
5585
  if (error.outputSize !== UNDEFINED_VALUE) {
5160
5586
  writer.size += error.outputSize;
@@ -5217,35 +5643,28 @@
5217
5643
  uncompressedSize
5218
5644
  } = options;
5219
5645
  let { version, compressionMethod } = options;
5220
- const compressed = !directory && (level > 0 || (level === UNDEFINED_VALUE && compressionMethod !== 0));
5646
+ const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
5647
+ ? (level === UNDEFINED_VALUE || level > 0)
5648
+ : compressionMethod !== COMPRESSION_METHOD_STORE);
5221
5649
  let rawLocalExtraFieldZip64;
5222
5650
  const uncompressedFile = passThrough || !compressed;
5223
- const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5224
- if (zip64) {
5225
- let rawLocalExtraFieldZip64Length = 4;
5226
- if (zip64UncompressedSize) {
5227
- rawLocalExtraFieldZip64Length += 8;
5228
- }
5229
- if (zip64CompressedSize) {
5230
- rawLocalExtraFieldZip64Length += 8;
5231
- }
5232
- rawLocalExtraFieldZip64 = new Uint8Array(rawLocalExtraFieldZip64Length);
5233
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5234
- setUint16(rawLocalExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5235
- setUint16(rawLocalExtraFieldZip64View, 2, getLength(rawLocalExtraFieldZip64) - 4);
5651
+ // entries without a data descriptor are always buffered (cf. getFileEntry), so the
5652
+ // zip64 extra field values can be patched into the local header before flushing it
5653
+ const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5654
+ const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
5655
+ if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
5656
+ // APPNOTE 4.5.3: the zip64 extra field of a local header must include both the
5657
+ // uncompressed and compressed size fields
5658
+ const length = 4 + 16;
5659
+ const extraFieldZip64 = createRecordWriter(length);
5660
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
5661
+ extraFieldZip64.uint16(length - 4);
5662
+ rawLocalExtraFieldZip64 = extraFieldZip64.array;
5236
5663
  if (zip64ExtraFieldComplete) {
5237
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5238
- let rawLocalExtraFieldZip64Offset = 4;
5239
- if (zip64UncompressedSize) {
5240
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5241
- rawLocalExtraFieldZip64Offset += 8;
5242
- }
5243
- if (zip64CompressedSize && uncompressedFile) {
5244
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5245
- rawLocalExtraFieldZip64Offset += 8;
5246
- }
5247
- if (rawLocalExtraFieldZip64Offset == 4) {
5248
- rawLocalExtraFieldZip64 = new Uint8Array();
5664
+ extraFieldZip64.uint64(uncompressedSize);
5665
+ if (uncompressedFile) {
5666
+ const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
5667
+ extraFieldZip64.uint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
5249
5668
  }
5250
5669
  }
5251
5670
  } else {
@@ -5253,11 +5672,11 @@
5253
5672
  }
5254
5673
  let rawExtraFieldAES;
5255
5674
  if (encrypted && !zipCrypto) {
5256
- rawExtraFieldAES = new Uint8Array(getLength(EXTRAFIELD_DATA_AES) + 2);
5257
- const extraFieldAESView = getDataView(rawExtraFieldAES);
5258
- setUint16(extraFieldAESView, 0, EXTRAFIELD_TYPE_AES);
5259
- arraySet(rawExtraFieldAES, EXTRAFIELD_DATA_AES, 2);
5260
- setUint8(extraFieldAESView, 8, encryptionStrength);
5675
+ const extraFieldAES = createRecordWriter(getLength(EXTRAFIELD_DATA_AES) + 2);
5676
+ extraFieldAES.uint16(EXTRAFIELD_TYPE_AES);
5677
+ extraFieldAES.bytes(EXTRAFIELD_DATA_AES);
5678
+ rawExtraFieldAES = extraFieldAES.array;
5679
+ rawExtraFieldAES[8] = encryptionStrength;
5261
5680
  } else {
5262
5681
  rawExtraFieldAES = new Uint8Array();
5263
5682
  }
@@ -5265,33 +5684,38 @@
5265
5684
  let rawExtraFieldExtendedTimestamp;
5266
5685
  let extraFieldExtendedTimestampFlag;
5267
5686
  if (extendedTimestamp) {
5268
- rawExtraFieldExtendedTimestamp = new Uint8Array(9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0));
5269
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldExtendedTimestamp);
5270
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5271
- setUint16(extraFieldExtendedTimestampView, 2, getLength(rawExtraFieldExtendedTimestamp) - 4);
5272
- extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5273
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5274
- let offset = 5;
5275
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastModDate.getTime() / 1000));
5276
- offset += 4;
5277
- if (lastAccessDate) {
5278
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastAccessDate.getTime() / 1000));
5279
- offset += 4;
5280
- }
5281
- if (creationDate) {
5282
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(creationDate.getTime() / 1000));
5687
+ const lastModTimeUnix = getTimeUnix(lastModDate);
5688
+ if (inUnixTimeRange(lastModTimeUnix)) {
5689
+ const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
5690
+ const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
5691
+ extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5692
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5693
+ extraFieldTimestamp.uint16(extraFieldTimestampLength - 4);
5694
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
5695
+ extraFieldTimestamp.uint32(lastModTimeUnix);
5696
+ if (lastAccessDate) {
5697
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(lastAccessDate)));
5698
+ }
5699
+ if (creationDate) {
5700
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(creationDate)));
5701
+ }
5702
+ rawExtraFieldExtendedTimestamp = extraFieldTimestamp.array;
5703
+ } else {
5704
+ // the date cannot be stored as a 32-bit time_t; the NTFS field replaces it
5705
+ rawExtraFieldExtendedTimestamp = new Uint8Array();
5283
5706
  }
5284
5707
  try {
5285
- rawExtraFieldNTFS = new Uint8Array(36);
5286
- const extraFieldNTFSView = getDataView(rawExtraFieldNTFS);
5287
5708
  const lastModTimeNTFS = getTimeNTFS(lastModDate);
5288
- setUint16(extraFieldNTFSView, 0, EXTRAFIELD_TYPE_NTFS);
5289
- setUint16(extraFieldNTFSView, 2, 32);
5290
- setUint16(extraFieldNTFSView, 8, EXTRAFIELD_TYPE_NTFS_TAG1);
5291
- setUint16(extraFieldNTFSView, 10, 24);
5292
- setBigUint64(extraFieldNTFSView, 12, lastModTimeNTFS);
5293
- setBigUint64(extraFieldNTFSView, 20, getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5294
- setBigUint64(extraFieldNTFSView, 28, getTimeNTFS(creationDate) || lastModTimeNTFS);
5709
+ const extraFieldNTFS = createRecordWriter(36);
5710
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
5711
+ extraFieldNTFS.uint16(32);
5712
+ extraFieldNTFS.skip(4);
5713
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
5714
+ extraFieldNTFS.uint16(24);
5715
+ extraFieldNTFS.uint64(lastModTimeNTFS);
5716
+ extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5717
+ extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
5718
+ rawExtraFieldNTFS = extraFieldNTFS.array;
5295
5719
  } catch {
5296
5720
  rawExtraFieldNTFS = new Uint8Array();
5297
5721
  }
@@ -5300,41 +5724,27 @@
5300
5724
  }
5301
5725
  let rawExtraFieldUnix;
5302
5726
  try {
5303
- const { uid, gid, unixMode, setuid, setgid, sticky, unixExtraFieldType } = options;
5304
- if (unixExtraFieldType && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE)) {
5727
+ const { uid, gid, unixExtraFieldType } = options;
5728
+ if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5305
5729
  const uidBytes = packUnixId(uid);
5306
5730
  const gidBytes = packUnixId(gid);
5307
- let modeArray = new Uint8Array();
5308
- if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && unixMode !== UNDEFINED_VALUE) {
5309
- let modeToWrite = unixMode & MAX_16_BITS;
5310
- if (setuid) {
5311
- modeToWrite |= FILE_ATTR_UNIX_SETUID_MASK;
5312
- }
5313
- if (setgid) {
5314
- modeToWrite |= FILE_ATTR_UNIX_SETGID_MASK;
5315
- }
5316
- if (sticky) {
5317
- modeToWrite |= FILE_ATTR_UNIX_STICKY_MASK;
5318
- }
5319
- modeArray = new Uint8Array(2);
5320
- const modeDataView = new DataView(modeArray.buffer);
5321
- modeDataView.setUint16(0, modeToWrite, true);
5322
- }
5323
- const payloadLength = 3 + uidBytes.length + gidBytes.length + modeArray.length;
5324
- rawExtraFieldUnix = new Uint8Array(4 + payloadLength);
5325
- const rawExtraFieldUnixView = getDataView(rawExtraFieldUnix);
5326
- setUint16(rawExtraFieldUnixView, 0, unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE ? EXTRAFIELD_TYPE_INFOZIP : EXTRAFIELD_TYPE_UNIX);
5327
- setUint16(rawExtraFieldUnixView, 2, payloadLength);
5328
- setUint8(rawExtraFieldUnixView, 4, 1);
5329
- setUint8(rawExtraFieldUnixView, 5, uidBytes.length);
5330
- let offset = 6;
5331
- arraySet(rawExtraFieldUnix, uidBytes, offset);
5332
- offset += uidBytes.length;
5333
- setUint8(rawExtraFieldUnixView, offset, gidBytes.length);
5334
- offset++;
5335
- arraySet(rawExtraFieldUnix, gidBytes, offset);
5336
- offset += gidBytes.length;
5337
- arraySet(rawExtraFieldUnix, modeArray, offset);
5731
+ const payloadLength = 3 + uidBytes.length + gidBytes.length;
5732
+ const extraFieldUnix = createRecordWriter(4 + payloadLength);
5733
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_INFOZIP);
5734
+ extraFieldUnix.uint16(payloadLength);
5735
+ extraFieldUnix.uint8(1);
5736
+ extraFieldUnix.uint8(uidBytes.length);
5737
+ extraFieldUnix.bytes(uidBytes);
5738
+ extraFieldUnix.uint8(gidBytes.length);
5739
+ extraFieldUnix.bytes(gidBytes);
5740
+ rawExtraFieldUnix = extraFieldUnix.array;
5741
+ } else if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5742
+ const extraFieldUnix = createRecordWriter(8);
5743
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_UNIX);
5744
+ extraFieldUnix.uint16(4);
5745
+ extraFieldUnix.uint16((uid === UNDEFINED_VALUE ? 0 : uid) & MAX_16_BITS);
5746
+ extraFieldUnix.uint16((gid === UNDEFINED_VALUE ? 0 : gid) & MAX_16_BITS);
5747
+ rawExtraFieldUnix = extraFieldUnix.array;
5338
5748
  } else {
5339
5749
  rawExtraFieldUnix = new Uint8Array();
5340
5750
  }
@@ -5352,8 +5762,11 @@
5352
5762
  rawExtraFieldAES[9] = compressionMethod;
5353
5763
  compressionMethod = COMPRESSION_METHOD_AES;
5354
5764
  }
5355
- const localExtraFieldZip64Length = zip64ExtraFieldComplete ? getLength(rawLocalExtraFieldZip64) : 0;
5765
+ const localExtraFieldZip64Length = writeLocalExtraFieldZip64 ? getLength(rawLocalExtraFieldZip64) : 0;
5356
5766
  const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5767
+ if (extraFieldLength > MAX_16_BITS) {
5768
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
5769
+ }
5357
5770
  const {
5358
5771
  headerArray,
5359
5772
  headerView,
@@ -5369,29 +5782,27 @@
5369
5782
  zip64UncompressedSize,
5370
5783
  extraFieldLength
5371
5784
  });
5372
- let localHeaderOffset = HEADER_SIZE;
5373
- const localHeaderArray = new Uint8Array(localHeaderOffset + getLength(rawFilename) + extraFieldLength);
5785
+ const localHeader = createRecordWriter(HEADER_SIZE + getLength(rawFilename) + extraFieldLength);
5786
+ const localHeaderArray = localHeader.array;
5374
5787
  const localHeaderView = getDataView(localHeaderArray);
5375
- setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE);
5376
- arraySet(localHeaderArray, headerArray, 4);
5377
- arraySet(localHeaderArray, rawFilename, localHeaderOffset);
5378
- localHeaderOffset += getLength(rawFilename);
5379
- if (zip64ExtraFieldComplete) {
5380
- arraySet(localHeaderArray, rawLocalExtraFieldZip64, localHeaderOffset);
5381
- }
5382
- localHeaderOffset += localExtraFieldZip64Length;
5383
- arraySet(localHeaderArray, rawExtraFieldAES, localHeaderOffset);
5384
- localHeaderOffset += getLength(rawExtraFieldAES);
5385
- arraySet(localHeaderArray, rawExtraFieldExtendedTimestamp, localHeaderOffset);
5386
- localHeaderOffset += getLength(rawExtraFieldExtendedTimestamp);
5387
- arraySet(localHeaderArray, rawExtraFieldNTFS, localHeaderOffset);
5388
- localHeaderOffset += getLength(rawExtraFieldNTFS);
5389
- arraySet(localHeaderArray, rawExtraFieldUnix, localHeaderOffset);
5390
- localHeaderOffset += getLength(rawExtraFieldUnix);
5391
- arraySet(localHeaderArray, rawExtraField, localHeaderOffset);
5788
+ localHeader.uint32(LOCAL_FILE_HEADER_SIGNATURE);
5789
+ localHeader.bytes(headerArray);
5790
+ localHeader.bytes(rawFilename);
5791
+ if (writeLocalExtraFieldZip64) {
5792
+ localHeader.bytes(rawLocalExtraFieldZip64);
5793
+ }
5794
+ localHeader.bytes(rawExtraFieldAES);
5795
+ localHeader.bytes(rawExtraFieldExtendedTimestamp);
5796
+ localHeader.bytes(rawExtraFieldNTFS);
5797
+ localHeader.bytes(rawExtraFieldUnix);
5798
+ localHeader.bytes(rawExtraField);
5392
5799
  if (dataDescriptor) {
5393
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, 0);
5394
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, 0);
5800
+ if (!zip64CompressedSize) {
5801
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5802
+ }
5803
+ if (!zip64UncompressedSize) {
5804
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5805
+ }
5395
5806
  }
5396
5807
  return {
5397
5808
  localHeaderArray,
@@ -5418,7 +5829,7 @@
5418
5829
  function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
5419
5830
  const { headerInfo } = entryInfo;
5420
5831
  let { localHeaderArray, extraFieldLength } = headerInfo;
5421
- let localHeaderArrayView = getDataView(localHeaderArray);
5832
+ let localHeaderArrayView;
5422
5833
  let extraBytesLength = 64 - ((zipWriterOffset + getLength(localHeaderArray)) % 64);
5423
5834
  if (extraBytesLength < 4) {
5424
5835
  extraBytesLength += 64;
@@ -5426,13 +5837,14 @@
5426
5837
  const rawExtraFieldUSDZ = new Uint8Array(extraBytesLength);
5427
5838
  const extraFieldUSDZView = getDataView(rawExtraFieldUSDZ);
5428
5839
  setUint16(extraFieldUSDZView, 0, EXTRAFIELD_TYPE_USDZ);
5429
- setUint16(extraFieldUSDZView, 2, extraBytesLength - 2);
5840
+ setUint16(extraFieldUSDZView, 2, extraBytesLength - 4);
5430
5841
  const previousLocalHeaderArray = localHeaderArray;
5431
5842
  headerInfo.localHeaderArray = localHeaderArray = new Uint8Array(getLength(previousLocalHeaderArray) + extraBytesLength);
5432
5843
  arraySet(localHeaderArray, previousLocalHeaderArray);
5433
5844
  arraySet(localHeaderArray, rawExtraFieldUSDZ, getLength(previousLocalHeaderArray));
5434
5845
  localHeaderArrayView = getDataView(localHeaderArray);
5435
5846
  setUint16(localHeaderArrayView, 28, extraFieldLength + extraBytesLength);
5847
+ headerInfo.localHeaderView = localHeaderArrayView;
5436
5848
  entryInfo.metadataSize += extraBytesLength;
5437
5849
  }
5438
5850
 
@@ -5555,37 +5967,32 @@
5555
5967
  }, localHeaderView, { dataDescriptor }) {
5556
5968
  if (!dataDescriptor) {
5557
5969
  if (!encrypted) {
5558
- setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + 4, signature);
5970
+ setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, signature);
5559
5971
  }
5560
5972
  if (!zip64CompressedSize) {
5561
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, compressedSize);
5973
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, compressedSize);
5562
5974
  }
5563
5975
  if (!zip64UncompressedSize) {
5564
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, uncompressedSize);
5976
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, uncompressedSize);
5565
5977
  }
5566
5978
  }
5567
5979
  if (zip64 && localExtraFieldZip64Length) {
5568
- let localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
5569
- if (zip64UncompressedSize) {
5570
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
5571
- localHeaderOffset += 8;
5572
- }
5573
- if (zip64CompressedSize) {
5574
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(compressedSize));
5575
- localHeaderOffset += 8;
5576
- }
5980
+ // the local zip64 extra field always contains both size slots
5981
+ const localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
5982
+ setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
5983
+ setBigUint64(localHeaderView, localHeaderOffset + 8, BigInt(compressedSize));
5577
5984
  }
5578
5985
  }
5579
5986
 
5580
5987
 
5581
5988
  async function closeFile(zipWriter, comment, options) {
5582
- const { files, writer } = zipWriter;
5583
- const { diskOffset } = writer;
5584
- let { diskNumber } = writer;
5585
- let offset = 0;
5989
+ const directoryDataLength = createDirectoryRecords(zipWriter.files);
5990
+ const { cdStartDiskNumber, cdStartDiskOffset } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
5991
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { cdStartDiskNumber, cdStartDiskOffset, directoryDataLength });
5992
+ }
5993
+
5994
+ function createDirectoryRecords(files) {
5586
5995
  let directoryDataLength = 0;
5587
- let directoryOffset = zipWriter.offset - diskOffset;
5588
- let filesLength = files.size;
5589
5996
  for (const [, fileEntry] of files) {
5590
5997
  const {
5591
5998
  rawFilename,
@@ -5602,24 +6009,27 @@
5602
6009
  uncompressedSize,
5603
6010
  compressedSize
5604
6011
  } = fileEntry;
5605
- const zip64Offset = fileEntry.offset > MAX_32_BITS;
5606
- const zip64DiskNumberStart = fileEntry.diskNumberStart > MAX_16_BITS;
6012
+ const zip64Offset = fileEntry.offset >= MAX_32_BITS;
6013
+ const zip64DiskNumberStart = fileEntry.diskNumberStart >= MAX_16_BITS;
5607
6014
  let rawExtraFieldZip64;
5608
6015
  if (zip64Offset || zip64DiskNumberStart || zip64UncompressedSize || zip64CompressedSize) {
5609
- let length = 4;
5610
- if (zip64UncompressedSize) length += 8;
5611
- if (zip64CompressedSize) length += 8;
5612
- if (zip64Offset) length += 8;
5613
- if (zip64DiskNumberStart) length += 4;
5614
- rawExtraFieldZip64 = new Uint8Array(length);
5615
- const zip64View = getDataView(rawExtraFieldZip64);
5616
- setUint16(zip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5617
- setUint16(zip64View, 2, length - 4);
5618
- let zip64FieldOffset = 4;
5619
- if (zip64UncompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(uncompressedSize)); zip64FieldOffset += 8; }
5620
- if (zip64CompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(compressedSize)); zip64FieldOffset += 8; }
5621
- if (zip64Offset) { setBigUint64(zip64View, zip64FieldOffset, BigInt(fileEntry.offset)); zip64FieldOffset += 8; }
5622
- if (zip64DiskNumberStart) { setUint32(zip64View, zip64FieldOffset, fileEntry.diskNumberStart); }
6016
+ const length = 4 + (zip64UncompressedSize ? 8 : 0) + (zip64CompressedSize ? 8 : 0) + (zip64Offset ? 8 : 0) + (zip64DiskNumberStart ? 4 : 0);
6017
+ const extraFieldZip64 = createRecordWriter(length);
6018
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
6019
+ extraFieldZip64.uint16(length - 4);
6020
+ if (zip64UncompressedSize) {
6021
+ extraFieldZip64.uint64(uncompressedSize);
6022
+ }
6023
+ if (zip64CompressedSize) {
6024
+ extraFieldZip64.uint64(compressedSize);
6025
+ }
6026
+ if (zip64Offset) {
6027
+ extraFieldZip64.uint64(fileEntry.offset);
6028
+ }
6029
+ if (zip64DiskNumberStart) {
6030
+ extraFieldZip64.uint32(fileEntry.diskNumberStart);
6031
+ }
6032
+ rawExtraFieldZip64 = extraFieldZip64.array;
5623
6033
  } else {
5624
6034
  rawExtraFieldZip64 = new Uint8Array();
5625
6035
  }
@@ -5627,32 +6037,41 @@
5627
6037
  fileEntry.zip64Offset = zip64Offset;
5628
6038
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
5629
6039
  let rawExtraFieldTimestamp;
5630
- if (extendedTimestamp) {
5631
- rawExtraFieldTimestamp = new Uint8Array(9);
5632
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldTimestamp);
5633
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5634
- setUint16(extraFieldExtendedTimestampView, 2, 5);
5635
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5636
- setUint32(extraFieldExtendedTimestampView, 5, Math.floor(lastModDate.getTime() / 1000));
6040
+ const lastModTimeUnix = getTimeUnix(lastModDate);
6041
+ if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
6042
+ const extraFieldTimestamp = createRecordWriter(9);
6043
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
6044
+ extraFieldTimestamp.uint16(5);
6045
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
6046
+ extraFieldTimestamp.uint32(lastModTimeUnix);
6047
+ rawExtraFieldTimestamp = extraFieldTimestamp.array;
5637
6048
  } else {
5638
6049
  rawExtraFieldTimestamp = new Uint8Array();
5639
6050
  }
5640
6051
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
5641
- directoryDataLength += 46 +
5642
- getLength(
5643
- rawFilename,
5644
- rawComment,
5645
- rawExtraFieldZip64,
5646
- rawExtraFieldAES,
5647
- rawExtraFieldNTFS,
5648
- rawExtraFieldUnix,
5649
- rawExtraFieldTimestamp,
5650
- rawExtraField);
6052
+ const extraFieldLength = getLength(
6053
+ rawExtraFieldZip64,
6054
+ rawExtraFieldAES,
6055
+ rawExtraFieldNTFS,
6056
+ rawExtraFieldUnix,
6057
+ rawExtraFieldTimestamp,
6058
+ rawExtraField);
6059
+ if (extraFieldLength > MAX_16_BITS) {
6060
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
6061
+ }
6062
+ directoryDataLength += CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
5651
6063
  }
6064
+ return directoryDataLength;
6065
+ }
6066
+
6067
+ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
6068
+ const { files, writer } = zipWriter;
5652
6069
  const directoryArray = new Uint8Array(directoryDataLength);
5653
- const directoryView = getDataView(directoryArray);
5654
6070
  await initStream(writer);
6071
+ let offset = 0;
5655
6072
  let directoryDiskOffset = 0;
6073
+ let cdStartDiskNumber = writer.diskNumber;
6074
+ let cdStartDiskOffset = writer.diskOffset;
5656
6075
  for (const [indexFileEntry, fileEntry] of Array.from(files.values()).entries()) {
5657
6076
  const {
5658
6077
  offset: fileEntryOffset,
@@ -5678,52 +6097,46 @@
5678
6097
  compressedSize
5679
6098
  } = fileEntry;
5680
6099
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5681
- setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE);
5682
- setUint16(directoryView, offset + 4, versionMadeBy);
6100
+ const directoryRecordLength = CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
6101
+ if (offset + directoryRecordLength - directoryDiskOffset > writer.availableSize) {
6102
+ await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
6103
+ directoryDiskOffset = offset;
6104
+ writer.availableSize = 0;
6105
+ await writeData(writer, new Uint8Array());
6106
+ }
6107
+ if (indexFileEntry == 0) {
6108
+ cdStartDiskNumber = writer.diskNumber;
6109
+ cdStartDiskOffset = writer.diskOffset;
6110
+ }
5683
6111
  if (!zip64UncompressedSize) {
5684
6112
  setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, uncompressedSize);
5685
6113
  }
5686
6114
  if (!zip64CompressedSize) {
5687
6115
  setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, compressedSize);
5688
6116
  }
5689
- arraySet(directoryArray, headerArray, offset + 6);
5690
- let directoryOffset = offset + HEADER_SIZE;
5691
- setUint16(directoryView, directoryOffset, extraFieldLength);
5692
- directoryOffset += 2;
5693
- setUint16(directoryView, directoryOffset, getLength(rawComment));
5694
- directoryOffset += 2;
5695
- setUint16(directoryView, directoryOffset, zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
5696
- directoryOffset += 2;
5697
- setUint16(directoryView, directoryOffset, internalFileAttributes);
5698
- directoryOffset += 2;
5699
- if (externalFileAttributes) {
5700
- setUint32(directoryView, directoryOffset, externalFileAttributes);
5701
- }
5702
- directoryOffset += 4;
5703
- setUint32(directoryView, directoryOffset, zip64Offset ? MAX_32_BITS : fileEntryOffset);
5704
- directoryOffset += 4;
5705
- arraySet(directoryArray, rawFilename, directoryOffset);
5706
- directoryOffset += getLength(rawFilename);
5707
- arraySet(directoryArray, rawExtraFieldZip64, directoryOffset);
5708
- directoryOffset += getLength(rawExtraFieldZip64);
5709
- arraySet(directoryArray, rawExtraFieldAES, directoryOffset);
5710
- directoryOffset += getLength(rawExtraFieldAES);
5711
- arraySet(directoryArray, rawExtraFieldExtendedTimestamp, directoryOffset);
5712
- directoryOffset += getLength(rawExtraFieldExtendedTimestamp);
5713
- arraySet(directoryArray, rawExtraFieldNTFS, directoryOffset);
5714
- directoryOffset += getLength(rawExtraFieldNTFS);
5715
- arraySet(directoryArray, rawExtraFieldUnix, directoryOffset);
5716
- directoryOffset += getLength(rawExtraFieldUnix);
5717
- arraySet(directoryArray, rawExtraField, directoryOffset);
5718
- directoryOffset += getLength(rawExtraField);
5719
- arraySet(directoryArray, rawComment, directoryOffset);
5720
- directoryOffset += getLength(rawComment);
5721
- if (offset - directoryDiskOffset > writer.availableSize) {
5722
- writer.availableSize = 0;
5723
- await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
5724
- directoryDiskOffset = offset;
5725
- }
5726
- offset = directoryOffset;
6117
+ if ((zip64Offset || zip64DiskNumberStart) && fileEntry.version < VERSION_ZIP64) {
6118
+ setUint16(headerView, HEADER_OFFSET_VERSION, VERSION_ZIP64);
6119
+ }
6120
+ const directoryRecord = createRecordWriter(directoryRecordLength);
6121
+ directoryRecord.uint32(CENTRAL_FILE_HEADER_SIGNATURE);
6122
+ directoryRecord.uint16(versionMadeBy);
6123
+ directoryRecord.bytes(headerArray.subarray(0, HEADER_SIZE - 4 - 2));
6124
+ directoryRecord.uint16(extraFieldLength);
6125
+ directoryRecord.uint16(getLength(rawComment));
6126
+ directoryRecord.uint16(zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
6127
+ directoryRecord.uint16(internalFileAttributes);
6128
+ directoryRecord.uint32(externalFileAttributes);
6129
+ directoryRecord.uint32(zip64Offset ? MAX_32_BITS : fileEntryOffset);
6130
+ directoryRecord.bytes(rawFilename);
6131
+ directoryRecord.bytes(rawExtraFieldZip64);
6132
+ directoryRecord.bytes(rawExtraFieldAES);
6133
+ directoryRecord.bytes(rawExtraFieldExtendedTimestamp);
6134
+ directoryRecord.bytes(rawExtraFieldNTFS);
6135
+ directoryRecord.bytes(rawExtraFieldUnix);
6136
+ directoryRecord.bytes(rawExtraField);
6137
+ directoryRecord.bytes(rawComment);
6138
+ arraySet(directoryArray, directoryRecord.array, offset);
6139
+ offset += directoryRecordLength;
5727
6140
  if (options.onprogress) {
5728
6141
  try {
5729
6142
  await options.onprogress(indexFileEntry + 1, files.size, new Entry(fileEntry));
@@ -5733,36 +6146,53 @@
5733
6146
  }
5734
6147
  }
5735
6148
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
6149
+ return { cdStartDiskNumber, cdStartDiskOffset };
6150
+ }
6151
+
6152
+ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
6153
+ const { writer } = zipWriter;
6154
+ const { cdStartDiskNumber, cdStartDiskOffset } = cdInfo;
6155
+ let { directoryDataLength } = cdInfo;
6156
+ let filesLength = zipWriter.files.size;
6157
+ let diskNumber = cdStartDiskNumber;
6158
+ let directoryOffset = zipWriter.offset - cdStartDiskOffset - (cdStartDiskNumber ? zipWriter.initialOffset : 0);
5736
6159
  let lastDiskNumber = writer.diskNumber;
5737
- const { availableSize } = writer;
5738
- if (availableSize < END_OF_CENTRAL_DIR_LENGTH) {
6160
+ if (writer.availableSize < END_OF_CENTRAL_DIR_LENGTH) {
5739
6161
  lastDiskNumber++;
5740
6162
  }
5741
6163
  let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5742
- if (directoryOffset > MAX_32_BITS || directoryDataLength > MAX_32_BITS || filesLength > MAX_16_BITS || lastDiskNumber > MAX_16_BITS) {
6164
+ if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || filesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
5743
6165
  if (zip64 === false) {
5744
6166
  throw new Error(ERR_UNSUPPORTED_FORMAT);
5745
6167
  } else {
5746
6168
  zip64 = true;
5747
6169
  }
5748
6170
  }
5749
- const endOfdirectoryArray = new Uint8Array(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
5750
- const endOfdirectoryView = getDataView(endOfdirectoryArray);
5751
- offset = 0;
6171
+ const commentLength = getLength(comment);
6172
+ if (commentLength > MAX_16_BITS) {
6173
+ throw new Error(ERR_INVALID_COMMENT);
6174
+ }
6175
+ const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6176
+ if (getLength(endOfdirectoryRecord.array) + commentLength > writer.availableSize) {
6177
+ writer.availableSize = 0;
6178
+ await writeData(writer, new Uint8Array());
6179
+ }
6180
+ lastDiskNumber = writer.diskNumber;
5752
6181
  if (zip64) {
5753
- setUint32(endOfdirectoryView, 0, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
5754
- setBigUint64(endOfdirectoryView, 4, BigInt(44));
5755
- setUint16(endOfdirectoryView, 12, 45);
5756
- setUint16(endOfdirectoryView, 14, 45);
5757
- setUint32(endOfdirectoryView, 16, lastDiskNumber);
5758
- setUint32(endOfdirectoryView, 20, diskNumber);
5759
- setBigUint64(endOfdirectoryView, 24, BigInt(filesLength));
5760
- setBigUint64(endOfdirectoryView, 32, BigInt(filesLength));
5761
- setBigUint64(endOfdirectoryView, 40, BigInt(directoryDataLength));
5762
- setBigUint64(endOfdirectoryView, 48, BigInt(directoryOffset));
5763
- setUint32(endOfdirectoryView, 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
5764
- setBigUint64(endOfdirectoryView, 64, BigInt(directoryOffset) + BigInt(directoryDataLength));
5765
- setUint32(endOfdirectoryView, 72, lastDiskNumber + 1);
6182
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
6183
+ endOfdirectoryRecord.uint64(44);
6184
+ endOfdirectoryRecord.uint16(45);
6185
+ endOfdirectoryRecord.uint16(45);
6186
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6187
+ endOfdirectoryRecord.uint32(diskNumber);
6188
+ endOfdirectoryRecord.uint64(filesLength);
6189
+ endOfdirectoryRecord.uint64(filesLength);
6190
+ endOfdirectoryRecord.uint64(directoryDataLength);
6191
+ endOfdirectoryRecord.uint64(directoryOffset);
6192
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
6193
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6194
+ endOfdirectoryRecord.uint64(BigInt(zipWriter.offset) + BigInt(directoryDataLength) - BigInt(writer.diskOffset) - BigInt(writer.diskNumber ? zipWriter.initialOffset : 0));
6195
+ endOfdirectoryRecord.uint32(lastDiskNumber + 1);
5766
6196
  const supportZip64SplitFile = getOptionValue(zipWriter, options, OPTION_SUPPORT_ZIP64_SPLIT_FILE, true);
5767
6197
  if (supportZip64SplitFile) {
5768
6198
  lastDiskNumber = MAX_16_BITS;
@@ -5771,29 +6201,40 @@
5771
6201
  filesLength = MAX_16_BITS;
5772
6202
  directoryOffset = MAX_32_BITS;
5773
6203
  directoryDataLength = MAX_32_BITS;
5774
- offset += ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
5775
- }
5776
- setUint32(endOfdirectoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE);
5777
- setUint16(endOfdirectoryView, offset + 4, lastDiskNumber);
5778
- setUint16(endOfdirectoryView, offset + 6, diskNumber);
5779
- setUint16(endOfdirectoryView, offset + 8, filesLength);
5780
- setUint16(endOfdirectoryView, offset + 10, filesLength);
5781
- setUint32(endOfdirectoryView, offset + 12, directoryDataLength);
5782
- setUint32(endOfdirectoryView, offset + 16, directoryOffset);
5783
- const commentLength = getLength(comment);
5784
- if (commentLength) {
5785
- if (commentLength <= MAX_16_BITS) {
5786
- setUint16(endOfdirectoryView, offset + 20, commentLength);
5787
- } else {
5788
- throw new Error(ERR_INVALID_COMMENT);
5789
- }
5790
6204
  }
5791
- await writeData(writer, endOfdirectoryArray);
6205
+ endOfdirectoryRecord.uint32(END_OF_CENTRAL_DIR_SIGNATURE);
6206
+ endOfdirectoryRecord.uint16(lastDiskNumber);
6207
+ endOfdirectoryRecord.uint16(diskNumber);
6208
+ endOfdirectoryRecord.uint16(filesLength);
6209
+ endOfdirectoryRecord.uint16(filesLength);
6210
+ endOfdirectoryRecord.uint32(directoryDataLength);
6211
+ endOfdirectoryRecord.uint32(directoryOffset);
6212
+ endOfdirectoryRecord.uint16(commentLength);
6213
+ await writeData(writer, endOfdirectoryRecord.array);
5792
6214
  if (commentLength) {
5793
6215
  await writeData(writer, comment);
5794
6216
  }
5795
6217
  }
5796
6218
 
6219
+ function createRecordWriter(length) {
6220
+ const array = new Uint8Array(length);
6221
+ const view = getDataView(array);
6222
+ let offset = 0;
6223
+ return {
6224
+ array,
6225
+ uint8: value => { setUint8(view, offset, value); offset += 1; },
6226
+ uint16: value => { setUint16(view, offset, value); offset += 2; },
6227
+ uint32: value => { setUint32(view, offset, value); offset += 4; },
6228
+ uint64: value => { setBigUint64(view, offset, BigInt(value)); offset += 8; },
6229
+ bytes: value => { arraySet(array, value, offset); offset += getLength(value); },
6230
+ skip: count => offset += count
6231
+ };
6232
+ }
6233
+
6234
+ function getSegmentOffset(zipWriter, writer) {
6235
+ return zipWriter.offset - writer.diskOffset - (writer.diskNumber ? zipWriter.initialOffset : 0);
6236
+ }
6237
+
5797
6238
  async function writeData(writer, array) {
5798
6239
  const { writable } = writer;
5799
6240
  const streamWriter = writable.getWriter();
@@ -5806,12 +6247,40 @@
5806
6247
  }
5807
6248
  }
5808
6249
 
6250
+ async function flushBufferedData(readable, writer, signal, onChunkWritten) {
6251
+ const streamWriter = writer.writable.getWriter();
6252
+ try {
6253
+ await readable.pipeTo(new WritableStream({
6254
+ async write(chunk) {
6255
+ await streamWriter.ready;
6256
+ await streamWriter.write(chunk);
6257
+ onChunkWritten(getLength(chunk));
6258
+ }
6259
+ }), { preventClose: true, preventAbort: true, signal });
6260
+ } finally {
6261
+ streamWriter.releaseLock();
6262
+ }
6263
+ }
6264
+
5809
6265
  function getTimeNTFS(date) {
5810
6266
  if (date) {
5811
6267
  return ((BigInt(date.getTime()) + BigInt(11644473600000)) * BigInt(10000));
5812
6268
  }
5813
6269
  }
5814
6270
 
6271
+ function getTimeUnix(date) {
6272
+ return Math.floor(date.getTime() / 1000);
6273
+ }
6274
+
6275
+ // the extended timestamp extra field stores dates as signed 32-bit time_t values
6276
+ function inUnixTimeRange(timeUnix) {
6277
+ return timeUnix >= MIN_UNIX_TIME && timeUnix <= MAX_UNIX_TIME;
6278
+ }
6279
+
6280
+ function clampUnixTime(timeUnix) {
6281
+ return Math.min(MAX_UNIX_TIME, Math.max(MIN_UNIX_TIME, timeUnix));
6282
+ }
6283
+
5815
6284
  function getOptionValue(zipWriter, options, name, defaultValue) {
5816
6285
  const result = options[name] === UNDEFINED_VALUE ? zipWriter.options[name] : options[name];
5817
6286
  return result === UNDEFINED_VALUE ? defaultValue : result;
@@ -5842,7 +6311,7 @@
5842
6311
  }
5843
6312
 
5844
6313
  function getDataView(array) {
5845
- return new DataView(array.buffer);
6314
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
5846
6315
  }
5847
6316
 
5848
6317
  function getLength(...arrayLikes) {
@@ -5858,30 +6327,39 @@
5858
6327
  uncompressedSize,
5859
6328
  compressedSize,
5860
6329
  lastModDate,
6330
+ rawLastModDate,
5861
6331
  rawFilename,
5862
6332
  zip64CompressedSize,
5863
6333
  zip64UncompressedSize,
5864
6334
  extraFieldLength
5865
6335
  }) {
5866
- const headerArray = new Uint8Array(HEADER_SIZE - 4);
6336
+ const headerRecord = createRecordWriter(HEADER_SIZE - 4);
6337
+ const headerArray = headerRecord.array;
5867
6338
  const headerView = getDataView(headerArray);
5868
- setUint16(headerView, 0, version);
5869
- setUint16(headerView, 2, bitFlag);
5870
- setUint16(headerView, 4, compressionMethod);
5871
- const dateArray = new Uint32Array(1);
5872
- const dateView = getDataView(dateArray);
5873
- setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
5874
- setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
5875
- const rawLastModDate = dateArray[0];
5876
- setUint32(headerView, 6, rawLastModDate);
6339
+ headerRecord.uint16(version);
6340
+ headerRecord.uint16(bitFlag);
6341
+ headerRecord.uint16(compressionMethod);
6342
+ if (rawLastModDate === UNDEFINED_VALUE) {
6343
+ const dateArray = new Uint32Array(1);
6344
+ const dateView = getDataView(dateArray);
6345
+ setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
6346
+ setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
6347
+ rawLastModDate = dateArray[0];
6348
+ }
6349
+ headerRecord.uint32(rawLastModDate);
6350
+ headerRecord.skip(4);
5877
6351
  if (zip64CompressedSize || compressedSize !== UNDEFINED_VALUE) {
5878
- setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, zip64CompressedSize ? MAX_32_BITS : compressedSize);
6352
+ headerRecord.uint32(zip64CompressedSize ? MAX_32_BITS : compressedSize);
6353
+ } else {
6354
+ headerRecord.skip(4);
5879
6355
  }
5880
6356
  if (zip64UncompressedSize || uncompressedSize !== UNDEFINED_VALUE) {
5881
- setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6357
+ headerRecord.uint32(zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6358
+ } else {
6359
+ headerRecord.skip(4);
5882
6360
  }
5883
- setUint16(headerView, 22, getLength(rawFilename));
5884
- setUint16(headerView, 24, extraFieldLength);
6361
+ headerRecord.uint16(getLength(rawFilename));
6362
+ headerRecord.uint16(extraFieldLength);
5885
6363
  return {
5886
6364
  headerArray,
5887
6365
  headerView,
@@ -5982,7 +6460,7 @@
5982
6460
  // ignored
5983
6461
  }
5984
6462
 
5985
- 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)});}
6463
+ 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)});}
5986
6464
 
5987
6465
  /*
5988
6466
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -6032,46 +6510,54 @@
6032
6510
 
6033
6511
  return new TransformStream({
6034
6512
  start() {
6035
- let result;
6036
- this.out = malloc(outBufferSize);
6037
- this.in = malloc(inBufferSize);
6038
- this.inBufferSize = inBufferSize;
6039
- this._scratch = new Uint8Array(outBufferSize);
6040
- if (isCompress) {
6041
- this._process = wasm.deflate_process;
6042
- this._last_consumed = wasm.deflate_last_consumed;
6043
- this._end = wasm.deflate_end;
6044
- this.streamHandle = wasm.deflate_new();
6045
- if (type === "gzip") {
6046
- result = wasm.deflate_init_gzip(this.streamHandle, level);
6047
- } else if (type === "deflate-raw") {
6048
- result = wasm.deflate_init_raw(this.streamHandle, level);
6049
- } else {
6050
- result = wasm.deflate_init(this.streamHandle, level);
6513
+ try {
6514
+ let result;
6515
+ this.out = malloc(outBufferSize);
6516
+ this.in = malloc(inBufferSize);
6517
+ this.inBufferSize = inBufferSize;
6518
+ if (!this.out || !this.in) {
6519
+ throw new Error("allocation failed");
6051
6520
  }
6052
- } else {
6053
- if (type === "deflate64-raw") {
6054
- this._process = wasm.inflate9_process;
6055
- this._last_consumed = wasm.inflate9_last_consumed;
6056
- this._end = wasm.inflate9_end;
6057
- this.streamHandle = wasm.inflate9_new();
6058
- result = wasm.inflate9_init_raw(this.streamHandle);
6521
+ this._scratch = new Uint8Array(outBufferSize);
6522
+ if (isCompress) {
6523
+ this._process = wasm.deflate_process;
6524
+ this._last_consumed = wasm.deflate_last_consumed;
6525
+ this._end = wasm.deflate_end;
6526
+ this.streamHandle = wasm.deflate_new();
6527
+ if (type === "gzip") {
6528
+ result = wasm.deflate_init_gzip(this.streamHandle, level);
6529
+ } else if (type === "deflate-raw") {
6530
+ result = wasm.deflate_init_raw(this.streamHandle, level);
6531
+ } else {
6532
+ result = wasm.deflate_init(this.streamHandle, level);
6533
+ }
6059
6534
  } else {
6060
- this._process = wasm.inflate_process;
6061
- this._last_consumed = wasm.inflate_last_consumed;
6062
- this._end = wasm.inflate_end;
6063
- this.streamHandle = wasm.inflate_new();
6064
- if (type === "deflate-raw") {
6065
- result = wasm.inflate_init_raw(this.streamHandle);
6066
- } else if (type === "gzip") {
6067
- result = wasm.inflate_init_gzip(this.streamHandle);
6535
+ if (type === "deflate64-raw") {
6536
+ this._process = wasm.inflate9_process;
6537
+ this._last_consumed = wasm.inflate9_last_consumed;
6538
+ this._end = wasm.inflate9_end;
6539
+ this.streamHandle = wasm.inflate9_new();
6540
+ result = wasm.inflate9_init_raw(this.streamHandle);
6068
6541
  } else {
6069
- result = wasm.inflate_init(this.streamHandle);
6542
+ this._process = wasm.inflate_process;
6543
+ this._last_consumed = wasm.inflate_last_consumed;
6544
+ this._end = wasm.inflate_end;
6545
+ this.streamHandle = wasm.inflate_new();
6546
+ if (type === "deflate-raw") {
6547
+ result = wasm.inflate_init_raw(this.streamHandle);
6548
+ } else if (type === "gzip") {
6549
+ result = wasm.inflate_init_gzip(this.streamHandle);
6550
+ } else {
6551
+ result = wasm.inflate_init(this.streamHandle);
6552
+ }
6070
6553
  }
6071
6554
  }
6072
- }
6073
- if (result !== 0) {
6074
- throw new Error("init failed:" + result);
6555
+ if (result !== 0) {
6556
+ throw new Error("init failed:" + result);
6557
+ }
6558
+ } catch (error) {
6559
+ disposeStream(this);
6560
+ throw error;
6075
6561
  }
6076
6562
  },
6077
6563
  transform(chunk, controller) {
@@ -6088,9 +6574,13 @@
6088
6574
  if (!this.in || this.inBufferSize < toRead) {
6089
6575
  if (this.in && free) {
6090
6576
  free(this.in);
6577
+ this.in = 0;
6091
6578
  }
6092
6579
  this.in = malloc(toRead);
6093
6580
  this.inBufferSize = toRead;
6581
+ if (!this.in) {
6582
+ throw new Error("allocation failed");
6583
+ }
6094
6584
  }
6095
6585
  heap.set(buffer.subarray(offset, offset + toRead), this.in);
6096
6586
  const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
@@ -6113,15 +6603,7 @@
6113
6603
  offset += consumed;
6114
6604
  }
6115
6605
  } catch (error) {
6116
- if (this._end && this.streamHandle) {
6117
- this._end(this.streamHandle);
6118
- }
6119
- if (this.in && free) {
6120
- free(this.in);
6121
- }
6122
- if (this.out && free) {
6123
- free(this.out);
6124
- }
6606
+ disposeStream(this);
6125
6607
  controller.error(error);
6126
6608
  }
6127
6609
  },
@@ -6152,21 +6634,35 @@
6152
6634
  } catch (error) {
6153
6635
  controller.error(error);
6154
6636
  } finally {
6155
- if (this._end && this.streamHandle) {
6156
- const result = this._end(this.streamHandle);
6157
- if (result !== 0) {
6158
- controller.error(new Error("end error:" + result));
6159
- }
6160
- }
6161
- if (this.in && free) {
6162
- free(this.in);
6163
- }
6164
- if (this.out && free) {
6165
- free(this.out);
6637
+ const result = disposeStream(this);
6638
+ if (result !== 0) {
6639
+ controller.error(new Error("end error:" + result));
6166
6640
  }
6167
6641
  }
6642
+ },
6643
+ cancel() {
6644
+ // release the stream handle and buffers when the pipeline is aborted,
6645
+ // they would be leaked in the process-lifetime wasm heap otherwise
6646
+ disposeStream(this);
6168
6647
  }
6169
6648
  });
6649
+
6650
+ function disposeStream(state) {
6651
+ let endResult = 0;
6652
+ if (state.streamHandle && state._end) {
6653
+ endResult = state._end(state.streamHandle);
6654
+ }
6655
+ state.streamHandle = 0;
6656
+ if (state.in && free) {
6657
+ free(state.in);
6658
+ }
6659
+ state.in = 0;
6660
+ if (state.out && free) {
6661
+ free(state.out);
6662
+ }
6663
+ state.out = 0;
6664
+ return endResult;
6665
+ }
6170
6666
  }
6171
6667
 
6172
6668
  class CompressionStreamZlib {
@@ -6336,12 +6832,15 @@
6336
6832
  */
6337
6833
 
6338
6834
 
6835
+ const ERR_ENTRY_EXISTS = "Entry filename already exists";
6836
+ const ERR_READABLE_CONSUMED = "Readable stream already consumed";
6837
+
6339
6838
  class ZipEntry {
6340
6839
 
6341
6840
  constructor(fs, name, params, parent) {
6342
6841
  const zipEntry = this;
6343
6842
  if (fs.root && parent && parent.getChildByName(name)) {
6344
- throw new Error("Entry filename already exists");
6843
+ throw new Error(ERR_ENTRY_EXISTS);
6345
6844
  }
6346
6845
  if (!params) {
6347
6846
  params = {};
@@ -6351,13 +6850,17 @@
6351
6850
  name,
6352
6851
  data: params.data,
6353
6852
  options: params.options,
6354
- id: fs.entries.length,
6853
+ id: fs.entryIdCounter++,
6355
6854
  parent,
6356
6855
  children: [],
6357
6856
  uncompressedSize: params.uncompressedSize || 0,
6358
6857
  passThrough: params.passThrough
6359
6858
  });
6360
- fs.entries.push(zipEntry);
6859
+ // detached entries (e.g. clones) are not registered until they are attached,
6860
+ // otherwise they could never be garbage collected
6861
+ if (parent || !fs.root) {
6862
+ fs.entries[zipEntry.id] = zipEntry;
6863
+ }
6361
6864
  if (parent) {
6362
6865
  zipEntry.parent.children.push(zipEntry);
6363
6866
  }
@@ -6395,7 +6898,7 @@
6395
6898
  rename(name) {
6396
6899
  const parent = this.parent;
6397
6900
  if (parent && parent.getChildByName(name)) {
6398
- throw new Error("Entry filename already exists");
6901
+ throw new Error(ERR_ENTRY_EXISTS);
6399
6902
  } else {
6400
6903
  this.name = name;
6401
6904
  }
@@ -6434,16 +6937,17 @@
6434
6937
  }
6435
6938
 
6436
6939
  isPasswordProtected() {
6437
- return this.data.encrypted;
6940
+ return Boolean(this.data && this.data.encrypted);
6438
6941
  }
6439
6942
 
6440
6943
  async checkPassword(password, options = {}) {
6441
6944
  const zipEntry = this;
6442
6945
  if (zipEntry.isPasswordProtected()) {
6443
- options.password = password;
6444
- options.checkPasswordOnly = true;
6445
6946
  try {
6446
- await zipEntry.data.getData(null, options);
6947
+ await zipEntry.data.getData(null, Object.assign({}, options, {
6948
+ password,
6949
+ checkPasswordOnly: true
6950
+ }));
6447
6951
  return true;
6448
6952
  } catch (error) {
6449
6953
  if (error.message == ERR_INVALID_PASSWORD) {
@@ -6477,8 +6981,15 @@
6477
6981
  return this.getData({ writable }, options);
6478
6982
  }
6479
6983
 
6480
- getArrayBuffer(options) {
6481
- return this.data.arrayBuffer(options);
6984
+ async getArrayBuffer(options) {
6985
+ // this.data may be a string, a Uint8Array, a data URI or a Blob depending on how the entry
6986
+ // was created, so retrieve the bytes through getUint8Array rather than assuming a Blob; this
6987
+ // also applies the options (password, signal, onprogress...) like the other getData() getters
6988
+ const array = await this.getUint8Array(options);
6989
+ // return the backing buffer directly when the array spans it, slicing the exact bytes otherwise
6990
+ return array.byteOffset || array.byteLength != array.buffer.byteLength
6991
+ ? array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength)
6992
+ : array.buffer;
6482
6993
  }
6483
6994
 
6484
6995
  replaceBlob(blob) {
@@ -6520,7 +7031,7 @@
6520
7031
  replaceReadable(readable) {
6521
7032
  Object.assign(this, {
6522
7033
  data: null,
6523
- Reader: function () { return { readable }; },
7034
+ Reader: getReadableReader(readable),
6524
7035
  Writer: null,
6525
7036
  reader: null
6526
7037
  });
@@ -6536,7 +7047,7 @@
6536
7047
 
6537
7048
  clone(deepClone) {
6538
7049
  const zipEntry = this;
6539
- const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name);
7050
+ const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name, zipEntry);
6540
7051
  if (deepClone) {
6541
7052
  clonedEntry.children = zipEntry.children.map(child => {
6542
7053
  const childClone = child.clone(deepClone);
@@ -6610,7 +7121,7 @@
6610
7121
 
6611
7122
  addReadable(name, readable, options = {}) {
6612
7123
  return addChild(this, name, {
6613
- Reader: function () { return { readable }; },
7124
+ Reader: getReadableReader(readable),
6614
7125
  options
6615
7126
  });
6616
7127
  }
@@ -6624,6 +7135,7 @@
6624
7135
  }
6625
7136
 
6626
7137
  addFile(file, options = {}) {
7138
+ options = Object.assign({}, options);
6627
7139
  if (!options.lastModDate) {
6628
7140
  options.lastModDate = new Date(file.lastModified);
6629
7141
  }
@@ -6690,11 +7202,15 @@
6690
7202
  try {
6691
7203
  const path = entry.filename.split("/");
6692
7204
  const name = path.pop();
6693
- path.forEach((pathPart, pathIndex) => {
7205
+ path.forEach(pathPart => {
6694
7206
  const previousParent = parent;
6695
7207
  parent = parent.getChildByName(pathPart);
6696
- if (!parent) {
6697
- parent = new ZipDirectoryEntry(this.fs, pathPart, { data: pathIndex == path.length - 1 ? entry : null }, previousParent);
7208
+ if (parent) {
7209
+ if (!parent.directory) {
7210
+ throw new Error(ERR_ENTRY_EXISTS);
7211
+ }
7212
+ } else {
7213
+ parent = new ZipDirectoryEntry(this.fs, pathPart, { data: null }, previousParent);
6698
7214
  importedEntries.push(parent);
6699
7215
  }
6700
7216
  });
@@ -6705,6 +7221,22 @@
6705
7221
  uncompressedSize: entry.uncompressedSize,
6706
7222
  passThrough: options.passThrough
6707
7223
  }));
7224
+ } else {
7225
+ let directoryEntry = parent;
7226
+ if (name) {
7227
+ directoryEntry = parent.getChildByName(name);
7228
+ if (directoryEntry) {
7229
+ if (!directoryEntry.directory) {
7230
+ throw new Error(ERR_ENTRY_EXISTS);
7231
+ }
7232
+ } else {
7233
+ directoryEntry = new ZipDirectoryEntry(this.fs, name, { data: null }, parent);
7234
+ importedEntries.push(directoryEntry);
7235
+ }
7236
+ }
7237
+ if (directoryEntry != this && !directoryEntry.data) {
7238
+ directoryEntry.data = entry;
7239
+ }
6708
7240
  }
6709
7241
  } catch (error) {
6710
7242
  try {
@@ -6720,14 +7252,15 @@
6720
7252
  return importedEntries;
6721
7253
  }
6722
7254
 
6723
- async exportZip(writer, options) {
7255
+ async exportZip(writer, options = {}) {
6724
7256
  const zipEntry = this;
7257
+ options = Object.assign({}, options);
6725
7258
  if (options.bufferedWrite === UNDEFINED_VALUE) {
6726
7259
  options.bufferedWrite = true;
6727
7260
  }
6728
- await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
7261
+ const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
6729
7262
  const zipWriter = new ZipWriter(writer, options);
6730
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options);
7263
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
6731
7264
  await zipWriter.close();
6732
7265
  return writer.getData ? writer.getData() : writer.writable;
6733
7266
  }
@@ -6773,7 +7306,15 @@
6773
7306
 
6774
7307
  remove(entry) {
6775
7308
  detach(entry);
6776
- this.entries[entry.id] = null;
7309
+ const removedEntries = [entry];
7310
+ while (removedEntries.length) {
7311
+ const removedEntry = removedEntries.pop();
7312
+ this.entries[removedEntry.id] = null;
7313
+ for (const child of removedEntry.children) {
7314
+ removedEntries.push(child);
7315
+ }
7316
+ }
7317
+ entry.parent = UNDEFINED_VALUE;
6777
7318
  }
6778
7319
 
6779
7320
  move(entry, destination) {
@@ -6783,12 +7324,17 @@
6783
7324
  if (destination.directory) {
6784
7325
  if (!destination.isDescendantOf(entry)) {
6785
7326
  if (entry != destination) {
6786
- if (destination.getChildByName(entry.name)) {
6787
- throw new Error("Entry filename already exists");
7327
+ const existingChild = destination.getChildByName(entry.name);
7328
+ if (existingChild) {
7329
+ if (existingChild != entry) {
7330
+ throw new Error(ERR_ENTRY_EXISTS);
7331
+ }
7332
+ } else {
7333
+ detach(entry);
7334
+ entry.parent = destination;
7335
+ destination.children.push(entry);
7336
+ registerEntries(this, entry);
6788
7337
  }
6789
- detach(entry);
6790
- entry.parent = destination;
6791
- destination.children.push(entry);
6792
7338
  }
6793
7339
  } else {
6794
7340
  throw new Error("Entry is a ancestor of target entry");
@@ -6805,6 +7351,11 @@
6805
7351
  for (let index = 0; node && index < path.length; index++) {
6806
7352
  node = node.getChildByName(path[index]);
6807
7353
  }
7354
+ if (!node) {
7355
+ // exclude detached entries, e.g. clones registered in `entries` but not attached
7356
+ node = this.entries.find(entry => entry && (entry == this.root || entry.isDescendantOf(this.root)) &&
7357
+ entry.getRelativeName() == fullname);
7358
+ }
6808
7359
  return node;
6809
7360
  }
6810
7361
 
@@ -6886,6 +7437,7 @@
6886
7437
  }
6887
7438
 
6888
7439
  importZip(reader, options) {
7440
+ resetFS(this);
6889
7441
  return this.root.importZip(reader, options);
6890
7442
  }
6891
7443
 
@@ -6905,6 +7457,10 @@
6905
7457
  return this.root.exportWritable(writable, options);
6906
7458
  }
6907
7459
 
7460
+ exportZip(writer, options) {
7461
+ return this.root.exportZip(writer, options);
7462
+ }
7463
+
6908
7464
  isPasswordProtected() {
6909
7465
  return this.root.isPasswordProtected();
6910
7466
  }
@@ -6918,15 +7474,26 @@
6918
7474
 
6919
7475
  function getTotalSize(entries, propertyName) {
6920
7476
  let size = 0;
6921
- entries.forEach(process);
7477
+ const pendingEntries = Array.from(entries);
7478
+ while (pendingEntries.length) {
7479
+ const entry = pendingEntries.pop();
7480
+ size += entry[propertyName] || 0;
7481
+ for (const child of entry.children) {
7482
+ pendingEntries.push(child);
7483
+ }
7484
+ }
6922
7485
  return size;
7486
+ }
6923
7487
 
6924
- function process(entry) {
6925
- size += entry[propertyName];
6926
- if (entry.children) {
6927
- entry.children.forEach(process);
7488
+ function getReadableReader(readable) {
7489
+ let consumed;
7490
+ return function () {
7491
+ if (consumed) {
7492
+ throw new Error(ERR_READABLE_CONSUMED);
6928
7493
  }
6929
- }
7494
+ consumed = true;
7495
+ return { readable };
7496
+ };
6930
7497
  }
6931
7498
 
6932
7499
  function getZipBlobReader(options) {
@@ -6941,7 +7508,7 @@
6941
7508
  async init() {
6942
7509
  const zipBlobReader = this;
6943
7510
  zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
6944
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options));
7511
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
6945
7512
  zipBlobReader.data = data;
6946
7513
  zipBlobReader.blobReader = new BlobReader(data);
6947
7514
  super.init();
@@ -6954,29 +7521,41 @@
6954
7521
  }
6955
7522
 
6956
7523
  async function initReaders(entry, options) {
6957
- if (entry.children.length) {
6958
- await Promise.all(entry.children.map(async child => {
7524
+ const fileEntries = [];
7525
+ const pendingEntries = [entry];
7526
+ // per-export map so concurrent exports do not share (and lock) the same readers
7527
+ const readers = new Map();
7528
+ while (pendingEntries.length) {
7529
+ const pendingEntry = pendingEntries.pop();
7530
+ for (const child of pendingEntry.children) {
6959
7531
  if (child.directory) {
6960
- await initReaders(child, options);
7532
+ pendingEntries.push(child);
6961
7533
  } else {
6962
- const reader = child.reader = new child.Reader(child.data, options);
6963
- try {
6964
- await initStream(reader);
6965
- } catch (error) {
6966
- try {
6967
- error.entryId = child.id;
6968
- error.cause = {
6969
- entry: child
6970
- };
6971
- } catch {
6972
- // ignored
6973
- }
6974
- throw error;
6975
- }
6976
- child.uncompressedSize = reader.size;
7534
+ fileEntries.push(child);
6977
7535
  }
6978
- }));
7536
+ }
6979
7537
  }
7538
+ await Promise.all(fileEntries.map(async child => {
7539
+ const reader = child.reader = new child.Reader(child.data, options);
7540
+ readers.set(child, reader);
7541
+ try {
7542
+ await initStream(reader);
7543
+ } catch (error) {
7544
+ try {
7545
+ error.entryId = child.id;
7546
+ error.cause = {
7547
+ entry: child
7548
+ };
7549
+ } catch {
7550
+ // ignored
7551
+ }
7552
+ throw error;
7553
+ }
7554
+ if (reader.size !== UNDEFINED_VALUE) {
7555
+ child.uncompressedSize = reader.size;
7556
+ }
7557
+ }));
7558
+ return readers;
6980
7559
  }
6981
7560
 
6982
7561
  function detach(entry) {
@@ -6990,7 +7569,7 @@
6990
7569
  }
6991
7570
  }
6992
7571
 
6993
- async function exportZip(zipWriter, entry, totalSize, options) {
7572
+ async function exportZip(zipWriter, entry, totalSize, options, readers) {
6994
7573
  const selectedEntry = entry;
6995
7574
  const entryOffsets = new Map();
6996
7575
  await process(zipWriter, entry);
@@ -7000,7 +7579,11 @@
7000
7579
 
7001
7580
  async function exportChild() {
7002
7581
  if (options.bufferedWrite) {
7003
- await Promise.allSettled(entry.children.map(processChild));
7582
+ const results = await Promise.allSettled(entry.children.map(processChild));
7583
+ const errorResult = results.find(result => result.status == "rejected");
7584
+ if (errorResult) {
7585
+ throw errorResult.reason;
7586
+ }
7004
7587
  } else {
7005
7588
  for (const child of entry.children) {
7006
7589
  await processChild(child);
@@ -7055,7 +7638,7 @@
7055
7638
  });
7056
7639
  }
7057
7640
  }
7058
- await zipWriter.add(name, child.reader, Object.assign({}, options, zipEntryOptions, childOptions, {
7641
+ await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
7059
7642
  directory: child.directory,
7060
7643
  onprogress: async indexProgress => {
7061
7644
  if (options.onprogress) {
@@ -7104,7 +7687,7 @@
7104
7687
  }
7105
7688
  } catch (error) {
7106
7689
  const message = error.message + (handle ? " (" + handle.name + ")" : "");
7107
- throw new Error(message);
7690
+ throw new Error(message, { cause: error });
7108
7691
  }
7109
7692
  }
7110
7693
  return addedEntries;
@@ -7164,9 +7747,21 @@
7164
7747
 
7165
7748
  function resetFS(fs) {
7166
7749
  fs.entries = [];
7750
+ fs.entryIdCounter = 0;
7167
7751
  fs.root = new ZipDirectoryEntry(fs);
7168
7752
  }
7169
7753
 
7754
+ function registerEntries(fs, entry) {
7755
+ const pendingEntries = [entry];
7756
+ while (pendingEntries.length) {
7757
+ const pendingEntry = pendingEntries.pop();
7758
+ fs.entries[pendingEntry.id] = pendingEntry;
7759
+ for (const child of pendingEntry.children) {
7760
+ pendingEntries.push(child);
7761
+ }
7762
+ }
7763
+ }
7764
+
7170
7765
  function addChild(parent, name, params, directory) {
7171
7766
  if (parent.directory) {
7172
7767
  return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
@@ -8842,6 +9437,7 @@
8842
9437
  exports.BlobWriter = BlobWriter;
8843
9438
  exports.Data64URIReader = Data64URIReader;
8844
9439
  exports.Data64URIWriter = Data64URIWriter;
9440
+ exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
8845
9441
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
8846
9442
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
8847
9443
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
@@ -8851,6 +9447,7 @@
8851
9447
  exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND;
8852
9448
  exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE;
8853
9449
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
9450
+ exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
8854
9451
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
8855
9452
  exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT;
8856
9453
  exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME;
@@ -8863,8 +9460,9 @@
8863
9460
  exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND;
8864
9461
  exports.ERR_OVERLAPPING_ENTRY = ERR_OVERLAPPING_ENTRY;
8865
9462
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9463
+ exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
8866
9464
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
8867
- exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION;
9465
+ exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
8868
9466
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
8869
9467
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
8870
9468
  exports.ERR_ZIP_NOT_EMPTY = ERR_ZIP_NOT_EMPTY;