@zip.js/zip.js 2.8.26 → 2.8.29

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 (53) hide show
  1. package/BENCHMARKS.md +168 -0
  2. package/README.md +2 -2
  3. package/deno.json +1 -1
  4. package/dist/zip-core.js +1113 -574
  5. package/dist/zip-core.min.js +1 -1
  6. package/dist/zip-fs-core.js +1209 -622
  7. package/dist/zip-fs-core.min.js +1 -1
  8. package/dist/zip-fs-native.js +1270 -632
  9. package/dist/zip-fs-native.min.js +1 -1
  10. package/dist/zip-fs.js +1347 -686
  11. package/dist/zip-fs.min.js +1 -1
  12. package/dist/zip-legacy.js +1114 -575
  13. package/dist/zip-legacy.min.js +1 -1
  14. package/dist/zip-module.wasm +0 -0
  15. package/dist/zip-native.js +1116 -577
  16. package/dist/zip-native.min.js +1 -1
  17. package/dist/zip-web-worker-native.js +1 -1
  18. package/dist/zip-web-worker.js +1 -1
  19. package/dist/zip.js +1193 -631
  20. package/dist/zip.min.js +1 -1
  21. package/eslint.config.mjs +6 -1
  22. package/index-native.cjs +1270 -632
  23. package/index-native.min.js +1 -1
  24. package/index.cjs +1347 -686
  25. package/index.d.ts +2451 -2355
  26. package/index.min.js +1 -1
  27. package/lib/core/codec-pool.js +39 -1
  28. package/lib/core/codec-worker.js +130 -35
  29. package/lib/core/configuration.js +3 -0
  30. package/lib/core/constants.js +6 -0
  31. package/lib/core/io.js +55 -25
  32. package/lib/core/options.js +2 -0
  33. package/lib/core/streams/aes-crypto-stream.js +12 -12
  34. package/lib/core/streams/codec-stream.js +11 -5
  35. package/lib/core/streams/codecs/sjcl.js +1 -33
  36. package/lib/core/streams/common-crypto.js +4 -4
  37. package/lib/core/streams/zip-crypto-stream.js +25 -15
  38. package/lib/core/streams/zip-entry-stream.js +89 -5
  39. package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
  40. package/lib/core/streams/zlib-wasm/zlib-streams.js +79 -56
  41. package/lib/core/streams/zlib-wasm/zlib-streams.wasm +0 -0
  42. package/lib/core/util/decode-cp437.js +1 -1
  43. package/lib/core/util/decode-text.js +2 -1
  44. package/lib/core/web-worker-base.js +12 -4
  45. package/lib/core/web-worker-inline-native.js +1 -1
  46. package/lib/core/web-worker-inline-wasm.js +1 -1
  47. package/lib/core/zip-fs.js +154 -55
  48. package/lib/core/zip-reader.js +185 -67
  49. package/lib/core/zip-writer.js +613 -376
  50. package/lib/core/zlib-streams-inline.js +1 -1
  51. package/lib/zip-core-reader.js +3 -1
  52. package/lib/zip-core-writer.js +1 -0
  53. package/package.json +20 -6
package/index.cjs CHANGED
@@ -44,6 +44,7 @@ const CENTRAL_FILE_HEADER_SIGNATURE = 0x02014b50;
44
44
  const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
45
45
  const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
46
46
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50;
47
+ const CENTRAL_FILE_HEADER_LENGTH = 46;
47
48
  const END_OF_CENTRAL_DIR_LENGTH = 22;
48
49
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20;
49
50
  const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56;
@@ -91,9 +92,11 @@ const VERSION_AES = 0x33;
91
92
  const DIRECTORY_SIGNATURE = "/";
92
93
 
93
94
  const HEADER_SIZE = 30;
95
+ const HEADER_OFFSET_VERSION = 0;
94
96
  const HEADER_OFFSET_SIGNATURE = 10;
95
97
  const HEADER_OFFSET_COMPRESSED_SIZE = 14;
96
98
  const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
99
+ const LOCAL_HEADER_COMMON_OFFSET = 4;
97
100
 
98
101
  const MAX_DATE = new Date(2107, 11, 31);
99
102
  const MIN_DATE = new Date(1980, 0, 1);
@@ -148,6 +151,7 @@ const DEFAULT_CONFIGURATION = {
148
151
  chunkSize: 64 * 1024,
149
152
  maxWorkers,
150
153
  terminateWorkerTimeout: 5000,
154
+ workerStarvationTimeout: 5000,
151
155
  useWebWorkers: true,
152
156
  useCompressionStream: true,
153
157
  CompressionStream: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
@@ -170,6 +174,7 @@ function configure(configuration) {
170
174
  chunkSize,
171
175
  maxWorkers,
172
176
  terminateWorkerTimeout,
177
+ workerStarvationTimeout,
173
178
  useCompressionStream,
174
179
  useWebWorkers,
175
180
  CompressionStream,
@@ -185,6 +190,7 @@ function configure(configuration) {
185
190
  setIfDefined("chunkSize", chunkSize);
186
191
  setIfDefined("maxWorkers", maxWorkers);
187
192
  setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
193
+ setIfDefined("workerStarvationTimeout", workerStarvationTimeout);
188
194
  setIfDefined("useCompressionStream", useCompressionStream);
189
195
  setIfDefined("useWebWorkers", useWebWorkers);
190
196
  setIfDefined("CompressionStream", CompressionStream);
@@ -199,7 +205,7 @@ function setIfDefined(propertyName, propertyValue) {
199
205
  }
200
206
  }
201
207
 
202
- function t(t){const e='(t=>{"function"==typeof define&&define.amd?define(t):t()})(function(){"use strict";const{Array:t,Object:e,Number:n,Math:s,Error:r,Uint8Array:o,Uint16Array:i,Uint32Array:c,Int32Array:a,Map:h,DataView:f,Promise:l,TextEncoder:u,crypto:w,postMessage:p,TransformStream:d,ReadableStream:y,WritableStream:m,CompressionStream:g,DecompressionStream:S}=self,b=void 0,v="undefined",k="function",z=[];for(let t=0;256>t;t++){let e=t;for(let t=0;8>t;t++)1&e?e=e>>>1^3988292384:e>>>=1;z[t]=e}class C{constructor(t){this.t=t||-1}append(t){let e=0|this.t;for(let n=0,s=0|t.length;s>n;n++)e=e>>>8^z[255&(e^t[n])];this.t=e}get(){return~this.t}}class A extends d{constructor(){let t;const e=new C;super({transform(t,n){e.append(t),n.enqueue(t)},flush(){const n=new o(4);new f(n.buffer).setUint32(0,e.get()),t.value=n}}),t=this}}const x={concat(t,e){if(0===t.length||0===e.length)return t.concat(e);const n=t[t.length-1],s=x.o(n);return 32===s?t.concat(e):x.i(e,s,0|n,t.slice(0,t.length-1))},h(t){const e=t.length;if(0===e)return 0;const n=t[e-1];return 32*(e-1)+x.o(n)},l(t,e){if(32*t.length<e)return t;const n=(t=t.slice(0,s.ceil(e/32))).length;return e&=31,n>0&&e&&(t[n-1]=x.u(e,t[n-1]&2147483648>>e-1,1)),t},u:(t,e,n)=>32===t?e:(n?0|e:e<<32-t)+1099511627776*t,o:t=>s.round(t/1099511627776)||32,i(t,e,n,s){for(void 0===s&&(s=[]);e>=32;e-=32)s.push(n),n=0;if(0===e)return s.concat(t);for(let r=0;r<t.length;r++)s.push(n|t[r]>>>e),n=t[r]<<32-e;const r=t.length?t[t.length-1]:0,o=x.o(r);return s.push(x.u(e+o&31,e+o>32?n:s.pop(),1)),s}},I={bytes:{p(t){const e=x.h(t)/8,n=new o(e);let s;for(let r=0;e>r;r++)3&r||(s=t[r/4]),n[r]=s>>>24,s<<=8;return n},m(t){const e=[];let n,s=0;for(n=0;n<t.length;n++)s=s<<8|t[n],3&~n||(e.push(s),s=0);return 3&n&&e.push(x.u(8*(3&n),s)),e}}},R=class{constructor(t){const e=this;e.blockSize=512,e.S=[1732584193,4023233417,2562383102,271733878,3285377520],e.v=[1518500249,1859775393,2400959708,3395469782],t?(e.k=t.k.slice(0),e.C=t.C.slice(0),e.A=t.A):e.reset()}reset(){const t=this;return t.k=t.S.slice(0),t.C=[],t.A=0,t}update(t){const e=this;"string"==typeof t&&(t=I.I.m(t));const n=e.C=x.concat(e.C,t),s=e.A,o=e.A=s+x.h(t);if(o>9007199254740991)throw new r("Cannot hash more than 2^53 - 1 bits");const i=new c(n);let a=0;for(let t=e.blockSize+s-(e.blockSize+s&e.blockSize-1);o>=t;t+=e.blockSize)e.R(i.subarray(16*a,16*(a+1))),a+=1;return n.splice(0,16*a),e}P(){const t=this;let e=t.C;const n=t.k;e=x.concat(e,[x.u(1,1)]);for(let t=e.length+2;15&t;t++)e.push(0);for(e.push(s.floor(t.A/4294967296)),e.push(0|t.A);e.length;)t.R(e.splice(0,16));return t.reset(),n}U(t,e,n,s){return t>19?t>39?t>59?t>79?void 0:e^n^s:e&n|e&s|n&s:e^n^s:e&n|~e&s}V(t,e){return e<<t|e>>>32-t}R(e){const n=this,r=n.k,o=t(80);for(let t=0;16>t;t++)o[t]=e[t];let i=r[0],c=r[1],a=r[2],h=r[3],f=r[4];for(let t=0;79>=t;t++){16>t||(o[t]=n.V(1,o[t-3]^o[t-8]^o[t-14]^o[t-16]));const e=n.V(5,i)+n.U(t,c,a,h)+f+o[t]+n.v[s.floor(t/20)]|0;f=h,h=a,a=n.V(30,c),c=i,i=e}r[0]=r[0]+i|0,r[1]=r[1]+c|0,r[2]=r[2]+a|0,r[3]=r[3]+h|0,r[4]=r[4]+f|0}},P={getRandomValues(t){const e=new c(t.buffer),n=t=>{let e=987654321;const n=4294967295;return()=>(e=36969*(65535&e)+(e>>16)&n,(((e<<16)+(t=18e3*(65535&t)+(t>>16)&n)&n)/4294967296+.5)*(s.random()>.5?1:-1))};for(let r,o=0;o<t.length;o+=4){const t=n(4294967296*(r||s.random()));r=987654071*t(),e[o/4]=4294967296*t()|0}return t}},U={importKey:t=>new U.M(I.bytes.m(t)),_(t,e,n,s){if(n=n||1e4,0>s||0>n)throw new r("invalid params to pbkdf2");const o=1+(s>>5)<<2;let i,c,a,h,l;const u=new ArrayBuffer(o),w=new f(u);let p=0;const d=x;for(e=I.bytes.m(e),l=1;(o||1)>p;l++){for(i=c=t.encrypt(d.concat(e,[l])),a=1;n>a;a++)for(c=t.encrypt(c),h=0;h<c.length;h++)i[h]^=c[h];for(a=0;(o||1)>p&&a<i.length;a++)w.setInt32(p,i[a]),p+=4}return u.slice(0,s/8)},M:class{constructor(t){const e=this,n=e.B=R,s=[[],[]];e.D=[new n,new n];const r=e.D[0].blockSize/32;t.length>r&&(t=(new n).update(t).P());for(let e=0;r>e;e++)s[0][e]=909522486^t[e],s[1][e]=1549556828^t[e];e.D[0].update(s[0]),e.D[1].update(s[1]),e.W=new n(e.D[0])}reset(){const t=this;t.W=new t.B(t.D[0]),t.K=!1}update(t){this.K=!0,this.W.update(t)}digest(){const t=this,e=t.W.P(),n=new t.B(t.D[1]).update(e).P();return t.reset(),n}encrypt(t){if(this.K)throw new r("encrypt on already updated hmac called!");return this.update(t),this.digest(t)}}},V=typeof w!=v&&typeof w.getRandomValues==k,M="Invalid password",_="Invalid signature",B="zipjs-abort-check-password";function D(t){return V?w.getRandomValues(t):P.getRandomValues(t)}const W=16,K={name:"PBKDF2"},E=e.assign({hash:{name:"HMAC"}},K),L=e.assign({iterations:1e3,hash:{name:"SHA-1"}},K),O=["deriveBits"],T=[8,12,16],j=[16,24,32],H=10,Z=[0,0,0,0],F=typeof w!=v,N=F&&w.subtle,q=F&&typeof N!=v,G=I.bytes,J=class{constructor(t){const e=this;e.L=[[[],[],[],[],[]],[[],[],[],[],[]]],e.L[0][0][0]||e.O();const n=e.L[0][4],s=e.L[1],o=t.length;let i,c,a,h=1;if(4!==o&&6!==o&&8!==o)throw new r("invalid aes key size");for(e.v=[c=t.slice(0),a=[]],i=o;4*o+28>i;i++){let t=c[i-1];(i%o===0||8===o&&i%o===4)&&(t=n[t>>>24]<<24^n[t>>16&255]<<16^n[t>>8&255]<<8^n[255&t],i%o===0&&(t=t<<8^t>>>24^h<<24,h=h<<1^283*(h>>7))),c[i]=c[i-o]^t}for(let t=0;i;t++,i--){const e=c[3&t?i:i-4];a[t]=4>=i||4>t?e:s[0][n[e>>>24]]^s[1][n[e>>16&255]]^s[2][n[e>>8&255]]^s[3][n[255&e]]}}encrypt(t){return this.T(t,0)}decrypt(t){return this.T(t,1)}O(){const t=this.L[0],e=this.L[1],n=t[4],s=e[4],r=[],o=[];let i,c,a,h;for(let t=0;256>t;t++)o[(r[t]=t<<1^283*(t>>7))^t]=t;for(let f=i=0;!n[f];f^=c||1,i=o[i]||1){let o=i^i<<1^i<<2^i<<3^i<<4;o=o>>8^255&o^99,n[f]=o,s[o]=f,h=r[a=r[c=r[f]]];let l=16843009*h^65537*a^257*c^16843008*f,u=257*r[o]^16843008*o;for(let n=0;4>n;n++)t[n][f]=u=u<<24^u>>>8,e[n][o]=l=l<<24^l>>>8}for(let n=0;5>n;n++)t[n]=t[n].slice(0),e[n]=e[n].slice(0)}T(t,e){if(4!==t.length)throw new r("invalid aes block size");const n=this.v[e],s=n.length/4-2,o=[0,0,0,0],i=this.L[e],c=i[0],a=i[1],h=i[2],f=i[3],l=i[4];let u,w,p,d=t[0]^n[0],y=t[e?3:1]^n[1],m=t[2]^n[2],g=t[e?1:3]^n[3],S=4;for(let t=0;s>t;t++)u=c[d>>>24]^a[y>>16&255]^h[m>>8&255]^f[255&g]^n[S],w=c[y>>>24]^a[m>>16&255]^h[g>>8&255]^f[255&d]^n[S+1],p=c[m>>>24]^a[g>>16&255]^h[d>>8&255]^f[255&y]^n[S+2],g=c[g>>>24]^a[d>>16&255]^h[y>>8&255]^f[255&m]^n[S+3],S+=4,d=u,y=w,m=p;for(let t=0;4>t;t++)o[e?3&-t:t]=l[d>>>24]<<24^l[y>>16&255]<<16^l[m>>8&255]<<8^l[255&g]^n[S++],u=d,d=y,y=m,m=g,g=u;return o}},Q=class{constructor(t,e){this.j=t,this.H=e,this.Z=e}reset(){this.Z=this.H}update(t){return this.F(this.j,t,this.Z)}N(t){if(255&~(t>>24))t+=1<<24;else{let e=t>>16&255,n=t>>8&255,s=255&t;255===e?(e=0,255===n?(n=0,255===s?s=0:++s):++n):++e,t=0,t+=e<<16,t+=n<<8,t+=s}return t}q(t){0===(t[0]=this.N(t[0]))&&(t[1]=this.N(t[1]))}F(t,e,n){let s;if(!(s=e.length))return[];const r=x.h(e);for(let r=0;s>r;r+=4){this.q(n);const s=t.encrypt(n);e[r]^=s[0],e[r+1]^=s[1],e[r+2]^=s[2],e[r+3]^=s[3]}return x.l(e,r)}},X=U.M;let Y=F&&q&&typeof N.importKey==k,$=F&&q&&typeof N.deriveBits==k;class tt extends d{constructor({password:t,rawPassword:n,signed:s,encryptionStrength:i,checkPasswordOnly:c}){super({start(){e.assign(this,{ready:new l(t=>this.G=t),password:rt(t,n),signed:s,J:i-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:i,G:a,ready:h}=n;s?(await(async(t,e,n,s)=>{const o=await st(t,e,n,it(s,0,T[e])),i=it(s,T[e]);if(o[0]!=i[0]||o[1]!=i[1])throw new r(M)})(n,i,s,it(t,0,T[i]+2)),t=it(t,T[i]+2),c?e.error(new r(B)):a()):await h;const f=new o(t.length-H-(t.length-H)%W);e.enqueue(nt(n,t,f,0,H,!0))},async flush(t){const{signed:e,X:n,Y:s,pending:i,ready:c}=this;if(s&&n){await c;const a=it(i,0,i.length-H),h=it(i,i.length-H);let f=new o;if(a.length){const t=at(G,a);s.update(t);const e=n.update(t);f=ct(G,e)}if(e){const t=it(ct(G,s.digest()),0,H);for(let e=0;H>e;e++)if(t[e]!=h[e])throw new r(_)}t.enqueue(f)}}})}}class et extends d{constructor({password:t,rawPassword:n,encryptionStrength:s}){let r;super({start(){e.assign(this,{ready:new l(t=>this.G=t),password:rt(t,n),J:s-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:r,G:i,ready:c}=n;let a=new o;s?(a=await(async(t,e,n)=>{const s=D(new o(T[e]));return ot(s,await st(t,e,n,s))})(n,r,s),i()):await c;const h=new o(a.length+t.length-t.length%W);h.set(a,0),e.enqueue(nt(n,t,h,a.length,0))},async flush(t){const{X:e,Y:n,pending:s,ready:i}=this;if(n&&e){await i;let c=new o;if(s.length){const t=e.update(at(G,s));n.update(t),c=ct(G,t)}r.signature=ct(G,n.digest()).slice(0,H),t.enqueue(ot(c,r.signature))}}}),r=this}}function nt(t,e,n,s,r,i){const{X:c,Y:a,pending:h}=t,f=e.length-r;let l;for(h.length&&(e=ot(h,e),n=((t,e)=>{if(e&&e>t.length){const n=t;(t=new o(e)).set(n,0)}return t})(n,f-f%W)),l=0;f-W>=l;l+=W){const t=at(G,it(e,l,l+W));i&&a.update(t);const r=c.update(t);i||a.update(r),n.set(ct(G,r),l+s)}return t.pending=it(e,l),n}async function st(n,s,r,i){n.password=null;const c=await(async(t,e,n,s,r)=>{if(!Y)return U.importKey(e);try{return await N.importKey("raw",e,n,!1,r)}catch{return Y=!1,U.importKey(e)}})(0,r,E,0,O),a=await(async(t,e,n)=>{if(!$)return U._(e,t.salt,L.iterations,n);try{return await N.deriveBits(t,e,n)}catch{return $=!1,U._(e,t.salt,L.iterations,n)}})(e.assign({salt:i},L),c,8*(2*j[s]+2)),h=new o(a),f=at(G,it(h,0,j[s])),l=at(G,it(h,j[s],2*j[s])),u=it(h,2*j[s]);return e.assign(n,{keys:{key:f,$:l,passwordVerification:u},X:new Q(new J(f),t.from(Z)),Y:new X(l)}),u}function rt(t,e){return e===b?(t=>{if(typeof u==v){const e=new o((t=unescape(encodeURIComponent(t))).length);for(let n=0;n<e.length;n++)e[n]=t.charCodeAt(n);return e}return(new u).encode(t)})(t):e}function ot(t,e){let n=t;return t.length+e.length&&(n=new o(t.length+e.length),n.set(t,0),n.set(e,t.length)),n}function it(t,e,n){return t.subarray(e,n)}function ct(t,e){return t.p(e)}function at(t,e){return t.m(e)}class ht extends d{constructor({password:t,passwordVerification:n,checkPasswordOnly:s}){super({start(){e.assign(this,{password:t,passwordVerification:n}),wt(this,t)},transform(t,e){const n=this;if(n.password){const e=lt(n,t.subarray(0,12));if(n.password=null,e.at(-1)!=n.passwordVerification)throw new r(M);t=t.subarray(12)}s?e.error(new r(B)):e.enqueue(lt(n,t))}})}}class ft extends d{constructor({password:t,passwordVerification:n}){super({start(){e.assign(this,{password:t,passwordVerification:n}),wt(this,t)},transform(t,e){const n=this;let s,r;if(n.password){n.password=null;const e=D(new o(12));e[11]=n.passwordVerification,s=new o(t.length+e.length),s.set(ut(n,e),0),r=12}else s=new o(t.length),r=0;s.set(ut(n,t),r),e.enqueue(s)}})}}function lt(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=dt(t)^e[s],pt(t,n[s]);return n}function ut(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=dt(t)^e[s],pt(t,e[s]);return n}function wt(t,n){const s=[305419896,591751049,878082192];e.assign(t,{keys:s,tt:new C(s[0]),et:new C(s[2])});for(let e=0;e<n.length;e++)pt(t,n.charCodeAt(e))}function pt(t,e){let[n,r,o]=t.keys;t.tt.append([e]),n=~t.tt.get(),r=mt(s.imul(mt(r+yt(n)),134775813)+1),t.et.append([r>>>24]),o=~t.et.get(),t.keys=[n,r,o]}function dt(t){const e=2|t.keys[2];return yt(s.imul(e,1^e)>>>8)}function yt(t){return 255&t}function mt(t){return 4294967295&t}class gt extends d{constructor(t,{chunkSize:e,nt:n,CompressionStream:s}){super({});const{compressed:r,encrypted:o,useCompressionStream:i,zipCrypto:c,signed:a,level:h}=t,l=this;let u,w,p=super.readable;o&&!c||!a||(u=new A,p=kt(p,u)),r&&(p=vt(p,i,{level:h,chunkSize:e},s,n,s)),o&&(c?p=kt(p,new ft(t)):(w=new et(t),p=kt(p,w))),bt(l,p,()=>{let t;o&&!c&&(t=w.signature),o&&!c||!a||(t=new f(u.value.buffer).getUint32(0)),l.signature=t})}}class St extends d{constructor(t,{chunkSize:e,st:n,DecompressionStream:s}){super({});const{zipCrypto:o,encrypted:i,signed:c,signature:a,compressed:h,useCompressionStream:l,rt:u}=t;let w,p,d=super.readable;i&&(o?d=kt(d,new ht(t)):(p=new tt(t),d=kt(d,p))),h&&(d=vt(d,l,{chunkSize:e,rt:u},s,n,s)),i&&!o||!c||(w=new A,d=kt(d,w)),bt(this,d,()=>{if((!i||o)&&c){const t=new f(w.value.buffer);if(a!=t.getUint32(0,!1))throw new r(_)}})}}function bt(t,n,s){n=kt(n,new d({flush:s})),e.defineProperty(t,"readable",{get:()=>n})}function vt(t,e,n,s,r,o){const i=e&&s?s:r||o,c=n.rt?"deflate64-raw":"deflate-raw";try{t=kt(t,new i(c,n))}catch(s){if(!e)throw s;if(r)t=kt(t,new r(c,n));else{if(!o)throw s;t=kt(t,new o(c,n))}}return t}function kt(t,e){return t.pipeThrough(e)}const zt="data",Ct="close";class At extends d{constructor(t,n){super({});const s=this,{codecType:o}=t;let i;o.startsWith("deflate")?i=gt:o.startsWith("inflate")&&(i=St),s.outputSize=0;let c=0;const a=new i(t,n),h=super.readable,f=new d({transform(t,e){t&&t.length&&(c+=t.length,e.enqueue(t))},flush(){e.assign(s,{inputSize:c})}}),l=new d({transform(e,n){if(e&&e.length&&(n.enqueue(e),s.outputSize+=e.length,t.outputSize!==b&&s.outputSize>t.outputSize))throw new r("Invalid uncompressed size")},flush(){const{signature:t}=a;e.assign(s,{signature:t,inputSize:c})}});e.defineProperty(s,"readable",{get:()=>h.pipeThrough(f).pipeThrough(a).pipeThrough(l)})}}class xt extends d{constructor(t){let e;super({transform:function n(s,r){if(e){const t=new o(e.length+s.length);t.set(e),t.set(s,e.length),s=t,e=null}s.length>t?(r.enqueue(s.slice(0,t)),n(s.slice(t),r)):e=s},flush(t){e&&e.length&&t.enqueue(e)}})}}const It=new h,Rt=new h;let Pt,Ut,Vt,Mt,_t,Bt=0;async function Dt(t){try{const{options:e,config:s}=t;if(!e.useCompressionStream)try{await self.initModule(t.config)}catch{e.useCompressionStream=!0}s.CompressionStream=self.CompressionStream,s.DecompressionStream=self.DecompressionStream;const r={highWaterMark:1},o=t.readable||new y({async pull(t){const e=new l(t=>It.set(Bt,t));Wt({type:"pull",messageId:Bt}),Bt=(Bt+1)%n.MAX_SAFE_INTEGER;const{value:s,done:r}=await e;t.enqueue(s),r&&t.close()}},r),i=t.writable||new m({async write(t){let e;const s=new l(t=>e=t);Rt.set(Bt,e),Wt({type:zt,value:t,messageId:Bt}),Bt=(Bt+1)%n.MAX_SAFE_INTEGER,await s}},r),c=new At(e,s);Pt=new AbortController;const{signal:a}=Pt;await o.pipeThrough(c).pipeThrough(new xt(s.chunkSize)).pipeTo(i,{signal:a,preventClose:!0,preventAbort:!0}),await i.getWriter().close();const{signature:h,inputSize:f,outputSize:u}=c;Wt({type:Ct,result:{signature:h,inputSize:f,outputSize:u}})}catch(t){t.outputSize=0,Kt(t)}}function Wt(t){let{value:e}=t;if(e)if(e.length)try{e=new o(e),t.value=e.buffer,p(t,[t.value])}catch{p(t)}else p(t);else p(t)}function Kt(t=new r("Unknown error")){const{message:e,stack:n,code:s,name:o,outputSize:i}=t;p({error:{message:e,stack:n,code:s,name:o,outputSize:i}})}function Et(t,e,n={}){const i="number"==typeof n.level?n.level:-1,c="number"==typeof n.ot?n.ot:65536,a="number"==typeof n.it?n.it:65536;return new d({start(){let n;if(this.ct=Vt(c),this.in=Vt(a),this.it=a,this.ht=new o(c),t?(this.ft=Ut.deflate_process,this.lt=Ut.deflate_last_consumed,this.ut=Ut.deflate_end,this.wt=Ut.deflate_new(),n="gzip"===e?Ut.deflate_init_gzip(this.wt,i):"deflate-raw"===e?Ut.deflate_init_raw(this.wt,i):Ut.deflate_init(this.wt,i)):"deflate64-raw"===e?(this.ft=Ut.inflate9_process,this.lt=Ut.inflate9_last_consumed,this.ut=Ut.inflate9_end,this.wt=Ut.inflate9_new(),n=Ut.inflate9_init_raw(this.wt)):(this.ft=Ut.inflate_process,this.lt=Ut.inflate_last_consumed,this.ut=Ut.inflate_end,this.wt=Ut.inflate_new(),n="deflate-raw"===e?Ut.inflate_init_raw(this.wt):"gzip"===e?Ut.inflate_init_gzip(this.wt):Ut.inflate_init(this.wt)),0!==n)throw new r("init failed:"+n)},transform(e,n){try{const i=e,a=new o(_t.buffer),h=this.ft,f=this.lt,l=this.ct,u=this.ht;let w=0;for(;w<i.length;){const e=s.min(i.length-w,32768);this.in&&this.it>=e||(this.in&&Mt&&Mt(this.in),this.in=Vt(e),this.it=e),a.set(i.subarray(w,w+e),this.in);const o=h(this.wt,this.in,e,l,c,0),p=16777215&o;if(p&&(u.set(a.subarray(l,l+p),0),n.enqueue(u.slice(0,p))),!t){const t=o>>24&255,e=128&t?t-256:t;if(0>e)throw new r("process error:"+e)}const d=f(this.wt);if(0===d)break;w+=d}}catch(t){this.ut&&this.wt&&this.ut(this.wt),this.in&&Mt&&Mt(this.in),this.ct&&Mt&&Mt(this.ct),n.error(t)}},flush(e){try{const n=new o(_t.buffer),s=this.ft,i=this.ct,a=this.ht;for(;;){const o=s(this.wt,0,0,i,c,4),h=16777215&o,f=o>>24&255;if(!t){const t=128&f?f-256:f;if(0>t)throw new r("process error:"+t)}if(h&&(a.set(n.subarray(i,i+h),0),e.enqueue(a.slice(0,h))),1===f||0===h)break}}catch(t){e.error(t)}finally{if(this.ut&&this.wt){const t=this.ut(this.wt);0!==t&&e.error(new r("end error:"+t))}this.in&&Mt&&Mt(this.in),this.ct&&Mt&&Mt(this.ct)}}})}addEventListener("message",({data:t})=>{const{type:e,messageId:n,value:s,done:r}=t;try{if("start"==e&&Dt(t),e==zt){const t=It.get(n);It.delete(n),t({value:new o(s),done:r})}if("ack"==e){const t=Rt.get(n);Rt.delete(n),t()}e==Ct&&Pt.abort()}catch(t){Kt(t)}});class Lt{constructor(t="deflate",e){return Et(!0,t,e)}}class Ot{constructor(t="deflate",e){return Et(!1,t,e)}}let Tt=!1;self.initModule=async t=>{try{const e=await(async(t,{baseURI:e})=>{if(!Tt){let n,s;try{try{s=new URL(t,e)}catch{}const r=await fetch(s);n=await r.arrayBuffer()}catch(e){if(!t.startsWith("data:application/wasm;base64,"))throw e;n=(t=>{const e=t.split(",")[1],n=atob(e),s=n.length,r=new o(s);for(let t=0;s>t;++t)r[t]=n.charCodeAt(t);return r.buffer})(t)}(t=>{if(Ut=t,({malloc:Vt,free:Mt,memory:_t}=Ut),"function"!=typeof Vt||"function"!=typeof Mt||!_t)throw Ut=Vt=Mt=_t=null,new r("Invalid WASM module")})((await WebAssembly.instantiate(n)).instance.exports),Tt=!0}})(t.wasmURI,t);return t.nt=Lt,t.st=Ot,e}catch{}}});\n';t({workerURI:t=>{const n="text/javascript";if(t){const t=new Blob([e],{type:n});return URL.createObjectURL(t)}return "data:"+n+","+encodeURIComponent(e)}});}
208
+ function t(t){const e='(t=>{"function"==typeof define&&define.amd?define(t):t()})(function(){"use strict";const{Array:t,Object:e,Number:n,Math:s,Error:r,Uint8Array:o,Uint16Array:i,Uint32Array:a,Int32Array:c,Map:l,DataView:w,Promise:f,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 w(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],w=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)+w+o[t]+n.k[s.floor(t/20)]|0;w=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]+w|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,f;const h=new ArrayBuffer(o),u=new w(h);let p=0;const d=A;for(e=P.bytes.m(e),f=1;(o||1)>p;f++){for(i=a=t.encrypt(d.concat(e,[f])),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 w=i=0;!n[w];w^=a||1,i=o[i]||1){let o=i^i<<1^i<<2^i<<3^i<<4;o=o>>8^255&o^99,n[w]=o,s[o]=w,l=r[c=r[a=r[w]]];let f=16843009*l^65537*c^257*a^16843008*w,h=257*r[o]^16843008*o;for(let n=0;4>n;n++)t[n][w]=h=h<<24^h>>>8,e[n][o]=f=f<<24^f>>>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],w=i[3],f=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]^w[255&g]^n[S],u=a[y>>>24]^c[m>>16&255]^l[g>>8&255]^w[255&d]^n[S+1],p=a[m>>>24]^c[g>>16&255]^l[d>>8&255]^w[255&y]^n[S+2],g=a[g>>>24]^c[d>>16&255]^l[y>>8&255]^w[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]=f[d>>>24]<<24^f[y>>16&255]<<16^f[m>>8&255]<<8^f[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 f(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 w=new o(t.length-O-(t.length-O)%_);e.enqueue(et(n,t,w,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 w=ot(it(q,n.digest()),0,O);let f=s.length<O?1:0;for(let t=0;O>t;t++)f|=w[t]^c[t];if(f)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 f(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 w=e.length-r;let f;for(n=((t,e)=>{if(e&&e>t.length){const n=t;(t=new o(e)).set(n,0)}return t})(n,s+(w-w%_)),f=0;w-_>=f;f+=_){const t=at(q,ot(e,f,f+_));i&&c.update(t);const r=a.update(t);i||c.update(r),n.set(it(q,r),f+s)}return t.pending=ot(e,f),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),w=at(q,ot(l,0,L[s])),f=at(q,ot(l,L[s],2*L[s])),h=ot(l,2*L[s]);return e.assign(n,{keys:{key:w,$:f,passwordVerification:h},X:new J(new G(w),t.from(H)),Y:new Q(f)}),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=wt(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(wt(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(ft(n,e),0),r=12}else s=new o(t.length),r=0;s.set(ft(n,t),r),e.enqueue(s)}})}}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,n[s]);return n}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,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,f=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(f,p,()=>{let t;o&&!a&&(t=u.signature),o&&!a||!c||(t=new w(h.value.buffer).getUint32(0)),f.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:f,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,f,{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 w(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";let c;try{c=new i(a,n)}catch(t){if(!e)throw t;if(r)c=new r(a,n);else{if(!o)throw t;c=new o(a,n)}}return((t,e)=>{const n=e.writable.getWriter(),s=t.getReader();return(async()=>{try{for(;;){await n.ready;const t=await s.read();if(t.done){await n.close();break}await n.write(t.value)}}catch(t){await(async(t,e)=>{try{await t.abort(e)}catch{}})(n,t),await(async(t,e)=>{try{await t.cancel(e)}catch{}})(s,t)}})(),e.readable})(t,c)}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,w=new d({transform(t,e){t&&t.length&&(a+=t.length,e.enqueue(t))},flush(){e.assign(s,{inputSize:a})}}),f=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(w).pipeThrough(c).pipeThrough(f)})}}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 f(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 f(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:w,inputSize:h,outputSize:u}=e;Tt({type:zt,result:{signature:w,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.wt?n.wt:65536,c="number"==typeof n.ft?n.ft:65536;return new d({start(){try{let n;if(this.ht=Dt(a),this.in=Dt(c),this.ft=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,w=this.yt,f=this.ht,h=this.ut;let u=0;for(;u<i.length;){const e=s.min(i.length-u,32768);if((!this.in||this.ft<e)&&(this.in&&Mt&&(Mt(this.in),this.in=0),this.in=Dt(e),this.ft=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,f,a,0),p=16777215&o;if(p&&(h.set(c.subarray(f,f+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=w(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,w=o>>24&255;if(!t){const t=128&w?w-256:w;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===w||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)}}Et.bt=!0,Lt.bt=!0;let Ot=!1;self.initModule=async t=>{try{const e=await(async(t,{baseURI:e})=>{if(!Ot){let n,s;try{try{s=new URL(t,e)}catch{}const r=await fetch(s);n=await r.arrayBuffer()}catch(e){if(!t.startsWith("data:application/wasm;base64,"))throw e;n=(t=>{const e=t.split(",")[1],n=atob(e),s=n.length,r=new o(s);for(let t=0;s>t;++t)r[t]=n.charCodeAt(t);return r.buffer})(t)}(t=>{if(Wt=t,({malloc:Dt,free:Mt,memory:Vt}=Wt),"function"!=typeof Dt||"function"!=typeof Mt||!Vt)throw Wt=Dt=Mt=Vt=null,new r("Invalid WASM module")})((await WebAssembly.instantiate(n)).instance.exports),Ot=!0}})(t.wasmURI,t);return t.nt=Et,t.st=Lt,e}catch{}}});\n';t({workerURI:t=>{const n="text/javascript";if(t){const t=new Blob([e],{type:n});return URL.createObjectURL(t)}return "data:"+n+","+encodeURIComponent(e)}});}
203
209
 
204
210
  /*
205
211
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -948,37 +954,6 @@ cipher.aes = class {
948
954
  }
949
955
  };
950
956
 
951
- /**
952
- * Random values
953
- * @namespace
954
- */
955
- const random = {
956
- /**
957
- * Generate random words with pure js, cryptographically not as strong & safe as native implementation.
958
- * @param {TypedArray} typedArray The array to fill.
959
- * @return {TypedArray} The random values.
960
- */
961
- getRandomValues(typedArray) {
962
- const words = new Uint32Array(typedArray.buffer);
963
- const r = (m_w) => {
964
- let m_z = 0x3ade68b1;
965
- const mask = 0xffffffff;
966
- return function () {
967
- m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
968
- m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
969
- const result = ((((m_z << 0x10) + m_w) & mask) / 0x100000000) + .5;
970
- return result * (Math.random() > .5 ? 1 : -1);
971
- };
972
- };
973
- for (let i = 0, rcache; i < typedArray.length; i += 4) {
974
- const _r = r((rcache || Math.random()) * 0x100000000);
975
- rcache = _r() * 0x3ade67b7;
976
- words[i / 4] = (_r() * 0x100000000) | 0;
977
- }
978
- return typedArray;
979
- }
980
- };
981
-
982
957
  /** @fileOverview CTR mode implementation.
983
958
  *
984
959
  * Special thanks to Roy Nicholson for pointing out a bug in our
@@ -1209,12 +1184,15 @@ const GET_RANDOM_VALUES_SUPPORTED = typeof crypto != UNDEFINED_TYPE && typeof cr
1209
1184
  const ERR_INVALID_PASSWORD = "Invalid password";
1210
1185
  const ERR_INVALID_SIGNATURE = "Invalid signature";
1211
1186
  const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
1187
+ const ERR_UNSUPPORTED_CRYPTO_API = "Crypto API not supported";
1212
1188
 
1213
1189
  function getRandomValues(array) {
1214
1190
  if (GET_RANDOM_VALUES_SUPPORTED) {
1215
1191
  return crypto.getRandomValues(array);
1216
1192
  } else {
1217
- return random.getRandomValues(array);
1193
+ // all supported runtimes expose crypto.getRandomValues; failing hard beats
1194
+ // silently generating predictable encryption salts
1195
+ throw new Error(ERR_UNSUPPORTED_CRYPTO_API);
1218
1196
  }
1219
1197
  }
1220
1198
 
@@ -1273,13 +1251,12 @@ let DERIVE_BITS_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && type
1273
1251
 
1274
1252
  class AESDecryptionStream extends TransformStream {
1275
1253
 
1276
- constructor({ password, rawPassword, signed, encryptionStrength, checkPasswordOnly }) {
1254
+ constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly }) {
1277
1255
  super({
1278
1256
  start() {
1279
1257
  Object.assign(this, {
1280
1258
  ready: new Promise(resolve => this.resolveReady = resolve),
1281
1259
  password: encodePassword(password, rawPassword),
1282
- signed,
1283
1260
  strength: encryptionStrength - 1,
1284
1261
  pending: new Uint8Array()
1285
1262
  });
@@ -1308,7 +1285,6 @@ class AESDecryptionStream extends TransformStream {
1308
1285
  },
1309
1286
  async flush(controller) {
1310
1287
  const {
1311
- signed,
1312
1288
  ctr,
1313
1289
  hmac,
1314
1290
  pending,
@@ -1325,13 +1301,15 @@ class AESDecryptionStream extends TransformStream {
1325
1301
  const decryptedChunk = ctr.update(encryptedChunk);
1326
1302
  decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
1327
1303
  }
1328
- if (signed) {
1329
- const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1330
- for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1331
- if (signature[indexSignature] != originalSignature[indexSignature]) {
1332
- throw new Error(ERR_INVALID_SIGNATURE);
1333
- }
1334
- }
1304
+ const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1305
+ // branch-free comparison: accumulate the differences instead of
1306
+ // short-circuiting on the first mismatching byte
1307
+ let invalidSignature = pending.length < SIGNATURE_LENGTH ? 1 : 0;
1308
+ for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1309
+ invalidSignature |= signature[indexSignature] ^ originalSignature[indexSignature];
1310
+ }
1311
+ if (invalidSignature) {
1312
+ throw new Error(ERR_INVALID_SIGNATURE);
1335
1313
  }
1336
1314
  controller.enqueue(decryptedChunkArray);
1337
1315
  }
@@ -1403,11 +1381,11 @@ function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignat
1403
1381
  hmac,
1404
1382
  pending
1405
1383
  } = aesCrypto;
1406
- const inputLength = input.length - paddingEnd;
1407
1384
  if (pending.length) {
1408
1385
  input = concat(pending, input);
1409
- output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
1410
1386
  }
1387
+ const inputLength = input.length - paddingEnd;
1388
+ output = expand(output, paddingStart + (inputLength - (inputLength % BLOCK_LENGTH)));
1411
1389
  let offset;
1412
1390
  for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
1413
1391
  const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
@@ -1555,21 +1533,24 @@ const HEADER_LENGTH = 12;
1555
1533
 
1556
1534
  class ZipCryptoDecryptionStream extends TransformStream {
1557
1535
 
1558
- constructor({ password, passwordVerification, checkPasswordOnly }) {
1536
+ constructor({ password, rawPassword, passwordVerification, checkPasswordOnly }) {
1559
1537
  super({
1560
1538
  start() {
1561
1539
  Object.assign(this, {
1562
1540
  password,
1541
+ rawPassword,
1563
1542
  passwordVerification
1564
1543
  });
1565
- createKeys(this, password);
1544
+ createKeys(this, password, rawPassword);
1566
1545
  },
1567
1546
  transform(chunk, controller) {
1568
1547
  const zipCrypto = this;
1569
- if (zipCrypto.password) {
1548
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1570
1549
  const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
1571
- zipCrypto.password = null;
1572
- if (decryptedHeader.at(-1) != zipCrypto.passwordVerification) {
1550
+ zipCrypto.password = zipCrypto.rawPassword = null;
1551
+ // verify the password with a branch-free comparison of the verification byte, mirroring
1552
+ // the constant-time AES HMAC signature check
1553
+ if ((decryptedHeader.at(-1) ^ zipCrypto.passwordVerification) != 0) {
1573
1554
  throw new Error(ERR_INVALID_PASSWORD);
1574
1555
  }
1575
1556
  chunk = chunk.subarray(HEADER_LENGTH);
@@ -1586,21 +1567,22 @@ class ZipCryptoDecryptionStream extends TransformStream {
1586
1567
 
1587
1568
  class ZipCryptoEncryptionStream extends TransformStream {
1588
1569
 
1589
- constructor({ password, passwordVerification }) {
1570
+ constructor({ password, rawPassword, passwordVerification }) {
1590
1571
  super({
1591
1572
  start() {
1592
1573
  Object.assign(this, {
1593
1574
  password,
1575
+ rawPassword,
1594
1576
  passwordVerification
1595
1577
  });
1596
- createKeys(this, password);
1578
+ createKeys(this, password, rawPassword);
1597
1579
  },
1598
1580
  transform(chunk, controller) {
1599
1581
  const zipCrypto = this;
1600
1582
  let output;
1601
1583
  let offset;
1602
- if (zipCrypto.password) {
1603
- zipCrypto.password = null;
1584
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1585
+ zipCrypto.password = zipCrypto.rawPassword = null;
1604
1586
  const header = getRandomValues(new Uint8Array(HEADER_LENGTH));
1605
1587
  header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification;
1606
1588
  output = new Uint8Array(chunk.length + header.length);
@@ -1635,25 +1617,31 @@ function encrypt(target, input) {
1635
1617
  return output;
1636
1618
  }
1637
1619
 
1638
- function createKeys(target, password) {
1620
+ function createKeys(target, password, rawPassword) {
1639
1621
  const keys = [0x12345678, 0x23456789, 0x34567890];
1640
1622
  Object.assign(target, {
1641
1623
  keys,
1642
1624
  crcKey0: new Crc32(keys[0]),
1643
1625
  crcKey2: new Crc32(keys[2])
1644
1626
  });
1645
- for (let index = 0; index < password.length; index++) {
1646
- updateKeys(target, password.charCodeAt(index));
1627
+ if (rawPassword) {
1628
+ for (let index = 0; index < rawPassword.length; index++) {
1629
+ updateKeys(target, rawPassword[index]);
1630
+ }
1631
+ } else {
1632
+ for (let index = 0; index < password.length; index++) {
1633
+ updateKeys(target, password.charCodeAt(index));
1634
+ }
1647
1635
  }
1648
1636
  }
1649
1637
 
1650
1638
  function updateKeys(target, byte) {
1651
- let [key0, key1, key2] = target.keys;
1639
+ let [, key1] = target.keys;
1652
1640
  target.crcKey0.append([byte]);
1653
- key0 = ~target.crcKey0.get();
1641
+ const key0 = ~target.crcKey0.get();
1654
1642
  key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
1655
1643
  target.crcKey2.append([key1 >>> 24]);
1656
- key2 = ~target.crcKey2.get();
1644
+ const key2 = ~target.crcKey2.get();
1657
1645
  target.keys = [key0, key1, key2];
1658
1646
  }
1659
1647
 
@@ -1700,6 +1688,7 @@ function getInt32(number) {
1700
1688
 
1701
1689
 
1702
1690
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
1691
+ const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
1703
1692
  const FORMAT_DEFLATE_RAW = "deflate-raw";
1704
1693
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
1705
1694
 
@@ -1756,6 +1745,7 @@ class InflateStream extends TransformStream {
1756
1745
  }
1757
1746
  if (compressed) {
1758
1747
  readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
1748
+ readable = mapInflateStreamError(readable);
1759
1749
  }
1760
1750
  if ((!encrypted || zipCrypto) && signed) {
1761
1751
  crc32Stream = new Crc32Stream();
@@ -1784,14 +1774,15 @@ function setReadable(stream, readable, flush) {
1784
1774
  function pipeThroughCommpressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib, CompressionStream) {
1785
1775
  const Stream = useCompressionStream && CompressionStreamNative ? CompressionStreamNative : CompressionStreamZlib || CompressionStream;
1786
1776
  const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
1777
+ let codecStream;
1787
1778
  try {
1788
- readable = pipeThrough(readable, new Stream(format, options));
1779
+ codecStream = new Stream(format, options);
1789
1780
  } catch (error) {
1790
1781
  if (useCompressionStream) {
1791
1782
  if (CompressionStreamZlib) {
1792
- readable = pipeThrough(readable, new CompressionStreamZlib(format, options));
1783
+ codecStream = new CompressionStreamZlib(format, options);
1793
1784
  } else if (CompressionStream) {
1794
- readable = pipeThrough(readable, new CompressionStream(format, options));
1785
+ codecStream = new CompressionStream(format, options);
1795
1786
  } else {
1796
1787
  throw error;
1797
1788
  }
@@ -1799,13 +1790,93 @@ function pipeThroughCommpressionStream(readable, useCompressionStream, options,
1799
1790
  throw error;
1800
1791
  }
1801
1792
  }
1802
- return readable;
1793
+ // The native CompressionStream/DecompressionStream and the pure-JS zlib port do not signal
1794
+ // backpressure on their writable side (their `ready` never pends), so a plain pipeThrough drains
1795
+ // the whole source into them and peak memory grows with the entry size. Awaiting each write()
1796
+ // paces the source to the codec's consumption rate, keeping streaming memory bounded. The WASM
1797
+ // codec already backpressures, so this is a no-op cost for it.
1798
+ return pipeThroughBackpressured(readable, codecStream);
1803
1799
  }
1804
1800
 
1805
1801
  function pipeThrough(readable, transformStream) {
1806
1802
  return readable.pipeThrough(transformStream);
1807
1803
  }
1808
1804
 
1805
+ // Like readable.pipeThrough(transformStream), but drives the writable side manually and awaits each
1806
+ // write() so that a codec which under-reports backpressure cannot pull the whole source into memory.
1807
+ // Errors propagate in both directions: a source error aborts the codec; a downstream cancel/error
1808
+ // (surfaced through the codec's writable rejecting) cancels the source.
1809
+ function pipeThroughBackpressured(readable, transformStream) {
1810
+ const writer = transformStream.writable.getWriter();
1811
+ const reader = readable.getReader();
1812
+ pump();
1813
+ return transformStream.readable;
1814
+
1815
+ async function pump() {
1816
+ try {
1817
+ for (; ;) {
1818
+ await writer.ready;
1819
+ const result = await reader.read();
1820
+ if (result.done) {
1821
+ await writer.close();
1822
+ break;
1823
+ }
1824
+ await writer.write(result.value);
1825
+ }
1826
+ } catch (error) {
1827
+ await abort(writer, error);
1828
+ await cancel(reader, error);
1829
+ }
1830
+ }
1831
+ }
1832
+
1833
+ async function abort(writer, error) {
1834
+ try {
1835
+ await writer.abort(error);
1836
+ } catch {
1837
+ // the writable may already be errored/closed
1838
+ }
1839
+ }
1840
+
1841
+ async function cancel(reader, error) {
1842
+ try {
1843
+ await reader.cancel(error);
1844
+ } catch {
1845
+ // the readable may already be errored/closed
1846
+ }
1847
+ }
1848
+
1849
+ // DecompressionStream implementations can fail with a message-less TypeError on malformed
1850
+ // input; give these errors an identifiable message (errors raised by the other stages of
1851
+ // the pipeline, e.g. ERR_INVALID_PASSWORD, always carry a message and pass through as-is)
1852
+ function mapInflateStreamError(readable) {
1853
+ const reader = readable.getReader();
1854
+ return new ReadableStream({
1855
+ async pull(controller) {
1856
+ let result;
1857
+ try {
1858
+ result = await reader.read();
1859
+ } catch (error) {
1860
+ if (error && error.message) {
1861
+ throw error;
1862
+ }
1863
+ const mappedError = new Error(ERR_INVALID_COMPRESSED_DATA);
1864
+ mappedError.cause = error;
1865
+ throw mappedError;
1866
+ }
1867
+ const { value, done } = result;
1868
+ if (done) {
1869
+ controller.close();
1870
+ } else {
1871
+ controller.enqueue(value);
1872
+ }
1873
+ },
1874
+ cancel(reason) {
1875
+ return reader.cancel(reason);
1876
+ }
1877
+ });
1878
+ }
1879
+
1809
1880
  /*
1810
1881
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
1811
1882
 
@@ -1835,6 +1906,7 @@ function pipeThrough(readable, transformStream) {
1835
1906
  */
1836
1907
 
1837
1908
 
1909
+ const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
1838
1910
  const MESSAGE_EVENT_TYPE = "message";
1839
1911
  const MESSAGE_START = "start";
1840
1912
  const MESSAGE_PULL = "pull";
@@ -1903,6 +1975,9 @@ class ChunkStream extends TransformStream {
1903
1975
 
1904
1976
  constructor(chunkSize) {
1905
1977
  let pendingChunk;
1978
+ if (!(chunkSize >= 1)) {
1979
+ chunkSize = DEFAULT_CHUNK_SIZE$1;
1980
+ }
1906
1981
  super({
1907
1982
  transform,
1908
1983
  flush(controller) {
@@ -1920,12 +1995,12 @@ class ChunkStream extends TransformStream {
1920
1995
  chunk = newChunk;
1921
1996
  pendingChunk = null;
1922
1997
  }
1923
- if (chunk.length > chunkSize) {
1924
- controller.enqueue(chunk.slice(0, chunkSize));
1925
- transform(chunk.slice(chunkSize), controller);
1926
- } else {
1927
- pendingChunk = chunk;
1998
+ let offset = 0;
1999
+ while (chunk.length - offset > chunkSize) {
2000
+ controller.enqueue(chunk.slice(offset, offset + chunkSize));
2001
+ offset += chunkSize;
1928
2002
  }
2003
+ pendingChunk = offset ? chunk.slice(offset) : chunk;
1929
2004
  }
1930
2005
  }
1931
2006
  }
@@ -1960,8 +2035,10 @@ class ChunkStream extends TransformStream {
1960
2035
 
1961
2036
 
1962
2037
  const MODULE_WORKER_OPTIONS = { type: "module" };
2038
+ const ERROR_EVENT_TYPE = "error";
2039
+ const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
1963
2040
 
1964
- let webWorkerSupported, webWorkerURI, webWorkerOptions;
2041
+ let webWorkerSupported, webWorkerSource, webWorkerURI, webWorkerOptions;
1965
2042
  let transferStreamsSupported = true;
1966
2043
  try {
1967
2044
  transferStreamsSupported = typeof structuredClone == FUNCTION_TYPE && structuredClone(new DOMException("", "AbortError")).code !== UNDEFINED_VALUE;
@@ -1980,8 +2057,9 @@ class CodecWorker {
1980
2057
  const { signal } = streamOptions;
1981
2058
  Object.assign(workerData, {
1982
2059
  busy: true,
2060
+ generation: (workerData.generation || 0) + 1,
1983
2061
  readable: readable
1984
- .pipeThrough(new ChunkStream(config.chunkSize))
2062
+ .pipeThrough(new ChunkStream(getChunkSize(config)))
1985
2063
  .pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
1986
2064
  writable,
1987
2065
  options: Object.assign({}, options),
@@ -2004,15 +2082,17 @@ class CodecWorker {
2004
2082
  });
2005
2083
  },
2006
2084
  onTaskFinished() {
2007
- const { resolveTerminated } = workerData;
2008
- if (resolveTerminated) {
2009
- workerData.resolveTerminated = null;
2010
- workerData.terminated = true;
2011
- workerData.worker.terminate();
2012
- resolveTerminated();
2085
+ if (workerData.busy) {
2086
+ const { resolveTerminated } = workerData;
2087
+ if (resolveTerminated) {
2088
+ workerData.resolveTerminated = null;
2089
+ workerData.terminated = true;
2090
+ workerData.worker.terminate();
2091
+ resolveTerminated();
2092
+ }
2093
+ workerData.busy = false;
2094
+ onTaskFinished(workerData);
2013
2095
  }
2014
- workerData.busy = false;
2015
- onTaskFinished(workerData);
2016
2096
  }
2017
2097
  });
2018
2098
  if (webWorkerSupported === UNDEFINED_VALUE) {
@@ -2081,6 +2161,7 @@ function createWebWorkerInterface(workerData, config) {
2081
2161
  }
2082
2162
  Object.assign(workerData, {
2083
2163
  worker,
2164
+ terminated: false,
2084
2165
  interface: {
2085
2166
  run: () => runWebWorker(workerData, { chunkSize, wasmURI, baseURI })
2086
2167
  }
@@ -2096,7 +2177,15 @@ async function runWorker$1({ options, readable, writable, onTaskFinished }, conf
2096
2177
  try {
2097
2178
  await initModule$1(config);
2098
2179
  } catch {
2099
- options.useCompressionStream = true;
2180
+ // The WASM module failed to load. Fall back to the native CompressionStream only if the
2181
+ // zlib codec that would otherwise run depends on that module; a self-contained codec
2182
+ // supplied through config (e.g. the pure-JS port) stays usable and is kept as requested.
2183
+ const ZlibStream = options.codecType.startsWith(CODEC_DEFLATE) ?
2184
+ config.CompressionStreamZlib :
2185
+ config.DecompressionStreamZlib;
2186
+ if (!ZlibStream || ZlibStream.requiresModule) {
2187
+ options.useCompressionStream = true;
2188
+ }
2100
2189
  }
2101
2190
  }
2102
2191
  codecStream = new CodecStream(options, config);
@@ -2135,37 +2224,85 @@ async function runWebWorker(workerData, config) {
2135
2224
  result
2136
2225
  });
2137
2226
  const { readable, options } = workerData;
2138
- const { writable, closed } = watchClosedStream(workerData.writable);
2139
- const streamsTransferred = sendMessage({
2140
- type: MESSAGE_START,
2141
- options,
2142
- config,
2143
- readable,
2144
- writable
2145
- }, workerData);
2227
+ const { writable, closed, abortPipe } = watchClosedStream(workerData.writable);
2228
+ let streamsTransferred;
2229
+ try {
2230
+ streamsTransferred = sendMessage({
2231
+ type: MESSAGE_START,
2232
+ options,
2233
+ config,
2234
+ readable,
2235
+ writable
2236
+ }, workerData);
2237
+ } catch (error) {
2238
+ abortPipe();
2239
+ try {
2240
+ await closed;
2241
+ } catch {
2242
+ // ignored
2243
+ }
2244
+ workerData.onTaskFinished();
2245
+ throw error;
2246
+ }
2146
2247
  if (!streamsTransferred) {
2147
2248
  Object.assign(workerData, {
2148
2249
  reader: readable.getReader(),
2149
2250
  writer: writable.getWriter()
2150
2251
  });
2151
2252
  }
2152
- const resultValue = await result;
2153
- if (!streamsTransferred) {
2154
- await writable.getWriter().close();
2253
+ try {
2254
+ const resultValue = await result;
2255
+ await closeWritable();
2256
+ await closed;
2257
+ return resultValue;
2258
+ } catch (error) {
2259
+ await closeWritable();
2260
+ // unblock the pipe watcher if the worker died before closing its end of the stream
2261
+ abortPipe();
2262
+ try {
2263
+ await closed;
2264
+ } catch {
2265
+ // ignored
2266
+ }
2267
+ throw error;
2268
+ }
2269
+
2270
+ async function closeWritable() {
2271
+ if (!streamsTransferred && !writable.locked) {
2272
+ try {
2273
+ await writable.getWriter().close();
2274
+ } catch {
2275
+ // ignored
2276
+ }
2277
+ }
2155
2278
  }
2156
- await closed;
2157
- return resultValue;
2158
2279
  }
2159
2280
 
2160
2281
  function watchClosedStream(writableSource) {
2282
+ const abortController = new AbortController();
2161
2283
  const { writable, readable } = new TransformStream();
2162
- const closed = readable.pipeTo(writableSource, { preventClose: true });
2163
- return { writable, closed };
2284
+ const closed = readable.pipeTo(writableSource, { preventClose: true, preventAbort: true, signal: abortController.signal });
2285
+ // the pipe can fail before `closed` is awaited (e.g. the destination write fails);
2286
+ // mark the rejection as handled so it cannot kill the process in the meantime
2287
+ closed.catch(() => { });
2288
+ return { writable, closed, abortPipe: () => abortController.abort() };
2289
+ }
2290
+
2291
+ function terminateWorker$1(workerData) {
2292
+ const { worker } = workerData;
2293
+ if (worker) {
2294
+ try {
2295
+ worker.terminate();
2296
+ } catch {
2297
+ // ignored
2298
+ }
2299
+ }
2300
+ workerData.interface = null;
2164
2301
  }
2165
2302
 
2166
2303
  function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true) {
2167
2304
  let worker, resolvedURI, resolvedOptions;
2168
- if (webWorkerURI === UNDEFINED_VALUE) {
2305
+ if (webWorkerURI === UNDEFINED_VALUE || webWorkerSource !== url) {
2169
2306
  // deno-lint-ignore valid-typeof
2170
2307
  const isFunctionURI = typeof url == FUNCTION_TYPE;
2171
2308
  if (isFunctionURI) {
@@ -2222,16 +2359,36 @@ function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true)
2222
2359
  }
2223
2360
  }
2224
2361
  }
2362
+ webWorkerSource = url;
2225
2363
  webWorkerURI = resolvedURI;
2226
2364
  webWorkerOptions = resolvedOptions;
2227
2365
  } else {
2228
2366
  worker = new Worker(webWorkerURI, webWorkerOptions);
2229
2367
  }
2230
2368
  worker.addEventListener(MESSAGE_EVENT_TYPE, event => onMessage(event, workerData));
2369
+ worker.addEventListener(ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2370
+ worker.addEventListener(MESSAGE_ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2231
2371
  return worker;
2232
2372
  }
2233
2373
 
2234
- function sendMessage(message, { worker, writer, onTaskFinished, transferStreams }) {
2374
+ function onWorkerError(event, workerData) {
2375
+ if (event.preventDefault) {
2376
+ event.preventDefault();
2377
+ }
2378
+ const { rejectResult, writer, onTaskFinished } = workerData;
2379
+ // the worker is unusable (e.g. its script failed to load); terminate it and
2380
+ // fail the current task instead of letting it hang forever
2381
+ terminateWorker$1(workerData);
2382
+ if (rejectResult) {
2383
+ rejectResult(event.error || new Error(event.message || ERROR_EVENT_TYPE));
2384
+ if (writer) {
2385
+ writer.releaseLock();
2386
+ }
2387
+ onTaskFinished();
2388
+ }
2389
+ }
2390
+
2391
+ function sendMessage(message, { worker, writer, transferStreams }) {
2235
2392
  try {
2236
2393
  const { value, readable, writable } = message;
2237
2394
  const transferables = [];
@@ -2265,14 +2422,16 @@ function sendMessage(message, { worker, writer, onTaskFinished, transferStreams
2265
2422
  if (writer) {
2266
2423
  writer.releaseLock();
2267
2424
  }
2268
- onTaskFinished();
2269
2425
  throw error;
2270
2426
  }
2271
2427
  }
2272
2428
 
2273
2429
  async function onMessage({ data }, workerData) {
2274
2430
  const { type, value, messageId, result, error } = data;
2275
- const { reader, writer, resolveResult, rejectResult, onTaskFinished } = workerData;
2431
+ const { reader, writer, resolveResult, rejectResult, onTaskFinished, generation } = workerData;
2432
+ // continuations below can settle after the worker slot has been reassigned to a new
2433
+ // task (e.g. a pending pull read failing late); they must not touch the new task
2434
+ const stale = () => workerData.generation != generation;
2276
2435
  try {
2277
2436
  if (error) {
2278
2437
  const { message, stack, code, name, outputSize } = error;
@@ -2282,23 +2441,32 @@ async function onMessage({ data }, workerData) {
2282
2441
  } else {
2283
2442
  if (type == MESSAGE_PULL) {
2284
2443
  const { value, done } = await reader.read();
2285
- sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2444
+ if (!stale()) {
2445
+ sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2446
+ }
2286
2447
  }
2287
2448
  if (type == MESSAGE_DATA) {
2288
2449
  await writer.ready;
2289
2450
  await writer.write(new Uint8Array(value));
2290
- sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2451
+ if (!stale()) {
2452
+ sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2453
+ }
2291
2454
  }
2292
2455
  if (type == MESSAGE_CLOSE) {
2293
2456
  close(null, result);
2294
2457
  }
2295
2458
  }
2296
2459
  } catch (error) {
2297
- sendMessage({ type: MESSAGE_CLOSE, messageId }, workerData);
2298
- close(error);
2460
+ if (!stale()) {
2461
+ terminateWorker$1(workerData);
2462
+ close(error);
2463
+ }
2299
2464
  }
2300
2465
 
2301
2466
  function close(error, result) {
2467
+ if (stale()) {
2468
+ return;
2469
+ }
2302
2470
  if (error) {
2303
2471
  rejectResult(error);
2304
2472
  } else {
@@ -2342,6 +2510,8 @@ async function onMessage({ data }, workerData) {
2342
2510
 
2343
2511
  let pool = [];
2344
2512
  const pendingRequests = [];
2513
+ let starvationTimeout;
2514
+ let starvationDelay;
2345
2515
 
2346
2516
  let indexWorker = 0;
2347
2517
 
@@ -2368,14 +2538,20 @@ async function runWorker(stream, workerOptions) {
2368
2538
  pool.push(workerData);
2369
2539
  return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
2370
2540
  } else {
2371
- return new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
2541
+ return new Promise(resolve => {
2542
+ pendingRequests.push({ resolve, stream, workerOptions });
2543
+ starvationDelay = config.workerStarvationTimeout;
2544
+ armStarvationTimeout();
2545
+ });
2372
2546
  }
2373
2547
  }
2374
2548
 
2375
2549
  function onTaskFinished(workerData) {
2550
+ clearStarvationTimeout();
2376
2551
  if (pendingRequests.length) {
2377
2552
  const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2378
2553
  resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
2554
+ armStarvationTimeout();
2379
2555
  } else if (workerData.worker) {
2380
2556
  clearTerminateTimeout(workerData);
2381
2557
  terminateWorker(workerData, workerOptions);
@@ -2385,6 +2561,34 @@ async function runWorker(stream, workerOptions) {
2385
2561
  }
2386
2562
  }
2387
2563
 
2564
+ function armStarvationTimeout() {
2565
+ if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
2566
+ starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
2567
+ }
2568
+ }
2569
+
2570
+ function clearStarvationTimeout() {
2571
+ if (starvationTimeout) {
2572
+ clearTimeout(starvationTimeout);
2573
+ starvationTimeout = null;
2574
+ }
2575
+ }
2576
+
2577
+ function onWorkerStarvation() {
2578
+ starvationTimeout = null;
2579
+ if (pendingRequests.length) {
2580
+ const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2581
+ const inlineWorkerOptions = Object.assign({}, workerOptions, { useWebWorkers: false, workerURI: UNDEFINED_VALUE });
2582
+ resolve(new CodecWorker({}, stream, inlineWorkerOptions, onInlineTaskFinished));
2583
+ armStarvationTimeout();
2584
+ }
2585
+ }
2586
+
2587
+ function onInlineTaskFinished() {
2588
+ clearStarvationTimeout();
2589
+ armStarvationTimeout();
2590
+ }
2591
+
2388
2592
  function terminateWorker(workerData, workerOptions) {
2389
2593
  const { config } = workerOptions;
2390
2594
  const { terminateWorkerTimeout } = config;
@@ -2455,6 +2659,7 @@ const ERR_WRITER_NOT_INITIALIZED = "Writer not initialized";
2455
2659
 
2456
2660
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
2457
2661
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
2662
+ const HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
2458
2663
  const HTTP_HEADER_CONTENT_RANGE = "Content-Range";
2459
2664
  const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges";
2460
2665
  const HTTP_HEADER_RANGE = "Range";
@@ -2579,7 +2784,7 @@ class Data64URIWriter extends Writer {
2579
2784
 
2580
2785
  writeUint8Array(array) {
2581
2786
  const writer = this;
2582
- let indexArray = 0;
2787
+ let indexArray;
2583
2788
  let dataString = writer.pending;
2584
2789
  const delta = writer.pending.length;
2585
2790
  writer.pending = "";
@@ -2589,12 +2794,10 @@ class Data64URIWriter extends Writer {
2589
2794
  for (; indexArray < array.length; indexArray++) {
2590
2795
  writer.pending += String.fromCharCode(array[indexArray]);
2591
2796
  }
2592
- if (dataString.length) {
2593
- if (dataString.length > 2) {
2594
- writer.data += btoa(dataString);
2595
- } else {
2596
- writer.pending += dataString;
2597
- }
2797
+ if (dataString.length > 2) {
2798
+ writer.data += btoa(dataString);
2799
+ } else {
2800
+ writer.pending = dataString + writer.pending;
2598
2801
  }
2599
2802
  }
2600
2803
 
@@ -2641,6 +2844,9 @@ class BlobWriter extends Stream {
2641
2844
  }
2642
2845
  });
2643
2846
  writer.blob = new Response(transformStream.readable, { headers }).blob();
2847
+ // mark early rejections (e.g. aborted pipe) as handled; awaiting getData() still
2848
+ // surfaces them
2849
+ writer.blob.catch(() => { });
2644
2850
  }
2645
2851
 
2646
2852
  getData() {
@@ -2725,7 +2931,8 @@ function createHttpReader(httpReader, url, options) {
2725
2931
  preventHeadRequest,
2726
2932
  useRangeHeader,
2727
2933
  forceRangeRequests,
2728
- combineSizeEocd
2934
+ combineSizeEocd,
2935
+ fetch
2729
2936
  } = options;
2730
2937
  options = Object.assign({}, options);
2731
2938
  delete options.preventHeadRequest;
@@ -2733,13 +2940,15 @@ function createHttpReader(httpReader, url, options) {
2733
2940
  delete options.forceRangeRequests;
2734
2941
  delete options.combineSizeEocd;
2735
2942
  delete options.useXHR;
2943
+ delete options.fetch;
2736
2944
  Object.assign(httpReader, {
2737
2945
  url,
2738
2946
  options,
2739
2947
  preventHeadRequest,
2740
2948
  useRangeHeader,
2741
2949
  forceRangeRequests,
2742
- combineSizeEocd
2950
+ combineSizeEocd,
2951
+ fetch
2743
2952
  });
2744
2953
  }
2745
2954
 
@@ -2758,7 +2967,10 @@ async function initHttpReader(httpReader, sendRequest, getRequestData) {
2758
2967
  throw new Error(ERR_HTTP_RANGE);
2759
2968
  } else {
2760
2969
  if (combineSizeEocd) {
2761
- httpReader.eocdCache = new Uint8Array(await response.arrayBuffer());
2970
+ const eocdCache = new Uint8Array(await response.arrayBuffer());
2971
+ if (response.status == 206 && eocdCache.length == END_OF_CENTRAL_DIR_LENGTH) {
2972
+ httpReader.eocdCache = eocdCache;
2973
+ }
2762
2974
  }
2763
2975
  let contentSize;
2764
2976
  const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
@@ -2804,7 +3016,18 @@ async function readUint8ArrayHttpReader(httpReader, index, length, sendRequest,
2804
3016
  if (response.status != 206) {
2805
3017
  throw new Error(ERR_HTTP_RANGE);
2806
3018
  }
2807
- return new Uint8Array(await response.arrayBuffer());
3019
+ const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
3020
+ if (contentRangeHeader) {
3021
+ const rangeStart = Number(contentRangeHeader.trim().split(/[\s-]+/)[1]);
3022
+ if (!Number.isNaN(rangeStart) && rangeStart != index) {
3023
+ throw new Error(ERR_HTTP_RANGE);
3024
+ }
3025
+ }
3026
+ const data = new Uint8Array(await response.arrayBuffer());
3027
+ if (data.length != length) {
3028
+ throw new Error(ERR_HTTP_RANGE);
3029
+ }
3030
+ return data;
2808
3031
  }
2809
3032
  } else {
2810
3033
  const { data } = httpReader;
@@ -2841,9 +3064,9 @@ async function getXMLHttpRequestData(httpReader) {
2841
3064
  async function getRequestData(httpReader, sendRequest) {
2842
3065
  const response = await sendRequest(HTTP_METHOD_GET, httpReader, getHeaders(httpReader));
2843
3066
  httpReader.data = new Uint8Array(await response.arrayBuffer());
2844
- if (!httpReader.size) {
2845
- httpReader.size = httpReader.data.length;
2846
- }
3067
+ // the downloaded content is authoritative, e.g. the Content-Length response header
3068
+ // of the HEAD request can be the encoded size when the content is compressed
3069
+ httpReader.size = httpReader.data.length;
2847
3070
  }
2848
3071
 
2849
3072
  async function getContentLength(httpReader, sendRequest, getRequestData) {
@@ -2852,7 +3075,7 @@ async function getContentLength(httpReader, sendRequest, getRequestData) {
2852
3075
  } else {
2853
3076
  const response = await sendRequest(HTTP_METHOD_HEAD, httpReader, getHeaders(httpReader));
2854
3077
  const contentLength = response.headers.get(HTTP_HEADER_CONTENT_LENGTH);
2855
- if (contentLength) {
3078
+ if (contentLength && !response.headers.get(HTTP_HEADER_CONTENT_ENCODING)) {
2856
3079
  httpReader.size = Number(contentLength);
2857
3080
  } else {
2858
3081
  await getRequestData(httpReader, httpReader.options);
@@ -2860,8 +3083,8 @@ async function getContentLength(httpReader, sendRequest, getRequestData) {
2860
3083
  }
2861
3084
  }
2862
3085
 
2863
- async function sendFetchRequest(method, { options, url }, headers) {
2864
- const response = await fetch(url, Object.assign({}, options, { method, headers }));
3086
+ async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
3087
+ const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
2865
3088
  if (response.status < 400) {
2866
3089
  return response;
2867
3090
  } else {
@@ -2907,7 +3130,8 @@ class HttpReader extends Reader {
2907
3130
  super();
2908
3131
  Object.assign(this, {
2909
3132
  url,
2910
- reader: options.useXHR ? new XHRReader(url, options) : new FetchReader(url, options)
3133
+ // an explicit fetch implementation takes precedence over useXHR
3134
+ reader: options.useXHR && !options.fetch ? new XHRReader(url, options) : new FetchReader(url, options)
2911
3135
  });
2912
3136
  }
2913
3137
 
@@ -2932,8 +3156,7 @@ class HttpReader extends Reader {
2932
3156
  class HttpRangeReader extends HttpReader {
2933
3157
 
2934
3158
  constructor(url, options = {}) {
2935
- options.useRangeHeader = true;
2936
- super(url, options);
3159
+ super(url, Object.assign({}, options, { useRangeHeader: true }));
2937
3160
  }
2938
3161
  }
2939
3162
 
@@ -3007,7 +3230,7 @@ class SplitDataReader extends Reader {
3007
3230
  reader.lastDiskNumber = 0;
3008
3231
  reader.lastDiskOffset = 0;
3009
3232
  await Promise.all(readers.map(async (diskReader, indexDiskReader) => {
3010
- await diskReader.init();
3233
+ await initStream(diskReader);
3011
3234
  if (indexDiskReader != readers.length - 1) {
3012
3235
  reader.lastDiskOffset += diskReader.size;
3013
3236
  }
@@ -3091,14 +3314,26 @@ class SplitDataWriter extends Stream {
3091
3314
  writer.diskOffset += diskSourceWriter.size;
3092
3315
  writer.diskNumber++;
3093
3316
  diskWriter = null;
3094
- await this.write(chunk.subarray(availableSize));
3317
+ // the next disk is not opened yet but its space is available; leaving a
3318
+ // stale value here would force a new disk for every subsequent write
3319
+ writer.availableSize = writer.maxSize;
3320
+ if (chunk.length > availableSize) {
3321
+ await this.write(chunk.subarray(availableSize));
3322
+ }
3095
3323
  } else {
3096
3324
  await writeChunk(chunk);
3097
3325
  }
3098
3326
  },
3099
3327
  async close() {
3100
- await diskWriter.ready;
3101
- await closeDisk();
3328
+ if (diskWriter) {
3329
+ await diskWriter.ready;
3330
+ await closeDisk();
3331
+ }
3332
+ },
3333
+ async abort(reason) {
3334
+ if (diskWriter) {
3335
+ await diskWriter.abort(reason);
3336
+ }
3102
3337
  }
3103
3338
  });
3104
3339
  Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
@@ -3113,7 +3348,6 @@ class SplitDataWriter extends Stream {
3113
3348
  await diskWriter.ready;
3114
3349
  await diskWriter.write(chunk);
3115
3350
  diskSourceWriter.size += chunkLength;
3116
- writer.size += chunkLength;
3117
3351
  writer.availableSize -= chunkLength;
3118
3352
  }
3119
3353
  }
@@ -3213,7 +3447,7 @@ function readUint8Array(reader, offset, size, diskNumber) {
3213
3447
 
3214
3448
  /* global TextDecoder */
3215
3449
 
3216
- const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3450
+ const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3217
3451
  const VALID_CP437 = CP437.length == 256;
3218
3452
 
3219
3453
  function decodeCP437(stringValue) {
@@ -3261,7 +3495,8 @@ function decodeText(value, encoding) {
3261
3495
  if (encoding && encoding.trim().toLowerCase() == "cp437") {
3262
3496
  return decodeCP437(value);
3263
3497
  } else {
3264
- return new TextDecoder(encoding).decode(value);
3498
+ // ignoreBOM keeps a leading U+FEFF in filenames/comments instead of dropping it
3499
+ return new TextDecoder(encoding, { ignoreBOM: true }).decode(value);
3265
3500
  }
3266
3501
  }
3267
3502
 
@@ -3438,6 +3673,7 @@ const OPTION_SIGNAL = "signal";
3438
3673
  const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
3439
3674
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
3440
3675
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
3676
+ const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
3441
3677
  const OPTION_CHECK_SIGNATURE = "checkSignature";
3442
3678
  const OPTION_USE_WEB_WORKERS = "useWebWorkers";
3443
3679
  const OPTION_USE_COMPRESSION_STREAM = "useCompressionStream";
@@ -3495,12 +3731,16 @@ const ERR_LOCAL_FILE_HEADER_NOT_FOUND = "Local file header not found";
3495
3731
  const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
3496
3732
  const ERR_ENCRYPTED = "File contains encrypted entry";
3497
3733
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
3498
- const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
3734
+ const ERR_UNSUPPORTED_COMPRESSION$1 = "Compression method not supported";
3499
3735
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
3500
3736
  const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
3737
+ const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
3501
3738
  const CHARSET_UTF8 = "utf-8";
3502
3739
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
3503
3740
  const CHARSET_CP437 = "cp437";
3741
+ // bits of the general purpose flag that change how an entry is interpreted; the level bits (1-2) are excluded
3742
+ // because they are informative only
3743
+ const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
3504
3744
  const ZIP64_PROPERTIES = [
3505
3745
  [PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
3506
3746
  [PROPERTY_NAME_COMPRESSED_SIZE, MAX_32_BITS],
@@ -3525,7 +3765,7 @@ class ZipReader {
3525
3765
  reader: new GenericReader(reader),
3526
3766
  options,
3527
3767
  config: getConfiguration(),
3528
- readRanges: []
3768
+ readRanges: new Map()
3529
3769
  });
3530
3770
  }
3531
3771
 
@@ -3558,21 +3798,30 @@ class ZipReader {
3558
3798
  const commentOffset = endOfDirectoryInfo.offset;
3559
3799
  const commentLength = getUint16(endOfDirectoryView, 20);
3560
3800
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
3801
+ const checkAmbiguity = getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY);
3802
+ if (checkAmbiguity && appendedDataOffset != reader.size) {
3803
+ throwAmbiguousArchive("appended data");
3804
+ }
3561
3805
  let lastDiskNumber = getUint16(endOfDirectoryView, 4);
3562
3806
  const expectedLastDiskNumber = reader.lastDiskNumber || 0;
3563
3807
  let diskNumber = getUint16(endOfDirectoryView, 6);
3564
- let filesLength = getUint16(endOfDirectoryView, 8);
3808
+ let filesLength = getUint16(endOfDirectoryView, 10);
3565
3809
  let prependedDataLength = 0;
3566
- let startOffset = 0;
3810
+ let startOffset;
3811
+ let zip64EndOfDirectory;
3567
3812
  if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
3568
- const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH);
3813
+ const endOfDirectoryLocatorArray = endOfDirectoryInfo.offset >= ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH ?
3814
+ await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH) :
3815
+ new Uint8Array();
3569
3816
  const endOfDirectoryLocatorView = getDataView$1(endOfDirectoryLocatorArray);
3570
- if (getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3817
+ if (endOfDirectoryLocatorArray.length == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH &&
3818
+ getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3571
3819
  directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8);
3572
3820
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3573
3821
  let endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3574
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
3575
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3822
+ const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH - (reader.lastDiskOffset || 0);
3823
+ if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
3824
+ directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
3576
3825
  const originalDirectoryDataOffset = directoryDataOffset;
3577
3826
  directoryDataOffset = expectedDirectoryDataOffset;
3578
3827
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3581,24 +3830,36 @@ class ZipReader {
3581
3830
  endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3582
3831
  endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3583
3832
  }
3584
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3833
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3585
3834
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
3586
3835
  }
3836
+ zip64EndOfDirectory = true;
3587
3837
  if (lastDiskNumber == MAX_16_BITS) {
3588
3838
  lastDiskNumber = getUint32(endOfDirectoryView, 16);
3839
+ } else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
3840
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3589
3841
  }
3590
3842
  if (diskNumber == MAX_16_BITS) {
3591
3843
  diskNumber = getUint32(endOfDirectoryView, 20);
3844
+ } else if (checkAmbiguity && diskNumber != getUint32(endOfDirectoryView, 20)) {
3845
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3592
3846
  }
3593
3847
  if (filesLength == MAX_16_BITS) {
3594
3848
  filesLength = getBigUint64(endOfDirectoryView, 32);
3849
+ } else if (checkAmbiguity && filesLength != getBigUint64(endOfDirectoryView, 32)) {
3850
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3595
3851
  }
3596
3852
  if (directoryDataLength == MAX_32_BITS) {
3597
3853
  directoryDataLength = getBigUint64(endOfDirectoryView, 40);
3854
+ } else if (checkAmbiguity && directoryDataLength != getBigUint64(endOfDirectoryView, 40)) {
3855
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3598
3856
  }
3599
- directoryDataOffset -= directoryDataLength;
3857
+ directoryDataOffset = getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
3600
3858
  }
3601
3859
  }
3860
+ const declaredDirectoryDataLength = directoryDataLength;
3861
+ const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
3862
+ (zip64EndOfDirectory ? ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
3602
3863
  if (directoryDataOffset >= reader.size) {
3603
3864
  prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
3604
3865
  directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
@@ -3613,8 +3874,11 @@ class ZipReader {
3613
3874
  let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3614
3875
  let directoryView = getDataView$1(directoryArray);
3615
3876
  if (directoryDataLength) {
3616
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength;
3617
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3877
+ if (directoryArray.length < 4) {
3878
+ throw new Error(ERR_BAD_FORMAT);
3879
+ }
3880
+ const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength - (reader.lastDiskOffset || 0);
3881
+ if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
3618
3882
  const originalDirectoryDataOffset = directoryDataOffset;
3619
3883
  directoryDataOffset = expectedDirectoryDataOffset;
3620
3884
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3624,8 +3888,8 @@ class ZipReader {
3624
3888
  directoryView = getDataView$1(directoryArray);
3625
3889
  }
3626
3890
  }
3627
- const expectedDirectoryDataLength = endOfDirectoryInfo.offset - directoryDataOffset - (reader.lastDiskOffset || 0);
3628
- if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0) {
3891
+ const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset - (reader.lastDiskOffset || 0);
3892
+ if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
3629
3893
  directoryDataLength = expectedDirectoryDataLength;
3630
3894
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3631
3895
  directoryView = getDataView$1(directoryArray);
@@ -3633,16 +3897,19 @@ class ZipReader {
3633
3897
  if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
3634
3898
  throw new Error(ERR_BAD_FORMAT);
3635
3899
  }
3900
+ startOffset = directoryDataOffset;
3636
3901
  const filenameEncoding = getOptionValue$1(zipReader, options, OPTION_FILENAME_ENCODING);
3637
3902
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
3903
+ const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
3904
+ let duplicateFilename;
3638
3905
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
3639
3906
  const fileEntry = new ZipEntry$1(reader, config, zipReader.options);
3640
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3907
+ if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3641
3908
  throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
3642
3909
  }
3643
3910
  readCommonHeader(fileEntry, directoryView, offset + 6);
3644
3911
  const languageEncodingFlag = Boolean(fileEntry.bitFlag.languageEncodingFlag);
3645
- const filenameOffset = offset + 46;
3912
+ const filenameOffset = offset + CENTRAL_FILE_HEADER_LENGTH;
3646
3913
  const extraFieldOffset = filenameOffset + fileEntry.filenameLength;
3647
3914
  const commentOffset = extraFieldOffset + fileEntry.extraFieldLength;
3648
3915
  const versionMadeBy = getUint16(directoryView, offset + 4);
@@ -3663,7 +3930,7 @@ class ZipReader {
3663
3930
  directory: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_DIR_MASK),
3664
3931
  archive: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_ARCHIVE_MASK)
3665
3932
  };
3666
- const offsetFileEntry = getUint32(directoryView, offset + 42) + prependedDataLength;
3933
+ const offsetFileEntry = getUint32(directoryView, offset + 42);
3667
3934
  const decode = getOptionValue$1(zipReader, options, OPTION_DECODE_TEXT) || decodeText;
3668
3935
  const rawFilenameEncoding = filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437;
3669
3936
  const rawCommentEncoding = commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437;
@@ -3676,6 +3943,7 @@ class ZipReader {
3676
3943
  comment = decodeText(rawComment, rawCommentEncoding);
3677
3944
  }
3678
3945
  Object.assign(fileEntry, {
3946
+ index: indexFile,
3679
3947
  versionMadeBy,
3680
3948
  msDosCompatible,
3681
3949
  compressedSize: 0,
@@ -3695,8 +3963,15 @@ class ZipReader {
3695
3963
  filename,
3696
3964
  comment
3697
3965
  });
3698
- startOffset = Math.max(offsetFileEntry, startOffset);
3699
3966
  readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
3967
+ fileEntry.offset += prependedDataLength;
3968
+ startOffset = Math.min(fileEntry.offset, startOffset);
3969
+ if (checkAmbiguity) {
3970
+ if (filenames.has(fileEntry.filename)) {
3971
+ duplicateFilename = true;
3972
+ }
3973
+ filenames.add(fileEntry.filename);
3974
+ }
3700
3975
  const unixExternalUpper = (fileEntry.externalFileAttributes >> 16) & MAX_16_BITS;
3701
3976
  if (fileEntry.unixMode === UNDEFINED_VALUE && (unixExternalUpper & (FILE_ATTR_UNIX_DEFAULT_MASK | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_TYPE_DIR)) != 0) {
3702
3977
  fileEntry.unixMode = unixExternalUpper;
@@ -3717,7 +3992,7 @@ class ZipReader {
3717
3992
  internalFileAttribute: fileEntry.internalFileAttributes,
3718
3993
  externalFileAttribute: fileEntry.externalFileAttributes,
3719
3994
  executable,
3720
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
3995
+ directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (fileEntry.filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
3721
3996
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
3722
3997
  });
3723
3998
  const entry = new Entry(fileEntry);
@@ -3740,6 +4015,15 @@ class ZipReader {
3740
4015
  }
3741
4016
  yield entry;
3742
4017
  }
4018
+ if (checkAmbiguity && offset != declaredDirectoryDataLength) {
4019
+ throwAmbiguousArchive("trailing central directory data");
4020
+ }
4021
+ if (duplicateFilename) {
4022
+ throwAmbiguousArchive("duplicate filename");
4023
+ }
4024
+ if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > 0))) {
4025
+ throwAmbiguousArchive("prepended data");
4026
+ }
3743
4027
  const extractPrependedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
3744
4028
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
3745
4029
  if (extractPrependedData) {
@@ -3779,9 +4063,21 @@ class ZipReaderStream {
3779
4063
  readable: (function () {
3780
4064
  const { readable, writable } = new TransformStream();
3781
4065
  if (value.getData) {
3782
- value.getData(writable);
4066
+ getData();
3783
4067
  return readable;
3784
4068
  }
4069
+
4070
+ async function getData() {
4071
+ try {
4072
+ await value.getData(writable);
4073
+ } catch (error) {
4074
+ try {
4075
+ await writable.abort(error);
4076
+ } catch {
4077
+ // ignored
4078
+ }
4079
+ }
4080
+ }
3785
4081
  })()
3786
4082
  };
3787
4083
  delete chunk.getData;
@@ -3806,6 +4102,7 @@ let ZipEntry$1 = class ZipEntry {
3806
4102
  const zipEntry = this;
3807
4103
  const {
3808
4104
  reader,
4105
+ index,
3809
4106
  offset,
3810
4107
  diskNumberStart,
3811
4108
  extraFieldAES,
@@ -3831,27 +4128,42 @@ let ZipEntry$1 = class ZipEntry {
3831
4128
  rawPassword = rawPassword && rawPassword.length && rawPassword;
3832
4129
  if (extraFieldAES) {
3833
4130
  if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
3834
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4131
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3835
4132
  }
3836
4133
  }
3837
4134
  if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64) && !passThrough) {
3838
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4135
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3839
4136
  }
3840
- if (getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
4137
+ if (dataArray.length < HEADER_SIZE || getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
3841
4138
  throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
3842
4139
  }
3843
4140
  readCommonHeader(localDirectory, dataView, 4);
3844
4141
  const {
3845
4142
  extraFieldLength,
3846
- filenameLength,
3847
- lastAccessDate,
3848
- creationDate
4143
+ filenameLength
3849
4144
  } = localDirectory;
3850
- localDirectory.rawExtraField = extraFieldLength ?
3851
- await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
3852
- new Uint8Array();
4145
+ const checkAmbiguity = getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY);
4146
+ let rawLocalFilename = new Uint8Array();
4147
+ if (checkAmbiguity && (filenameLength || extraFieldLength)) {
4148
+ const trailingDataArray = await readUint8Array(reader, offset + HEADER_SIZE, filenameLength + extraFieldLength, diskNumberStart);
4149
+ rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
4150
+ localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
4151
+ } else {
4152
+ localDirectory.rawExtraField = extraFieldLength ?
4153
+ await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
4154
+ new Uint8Array();
4155
+ }
3853
4156
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
3854
- Object.assign(fileEntry, { lastAccessDate, creationDate });
4157
+ if (checkAmbiguity) {
4158
+ checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
4159
+ }
4160
+ const { lastAccessDate, creationDate } = localDirectory;
4161
+ if (lastAccessDate) {
4162
+ fileEntry.lastAccessDate = lastAccessDate;
4163
+ }
4164
+ if (creationDate) {
4165
+ fileEntry.creationDate = creationDate;
4166
+ }
3855
4167
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
3856
4168
  const zipCrypto = encrypted && !extraFieldAES;
3857
4169
  if (!passThrough) {
@@ -3897,7 +4209,7 @@ let ZipEntry$1 = class ZipEntry {
3897
4209
  outputSize: passThrough ? compressedSize : uncompressedSize,
3898
4210
  signature,
3899
4211
  compressed: compressionMethod != 0 && !passThrough,
3900
- encrypted: zipEntry.encrypted && !passThrough,
4212
+ encrypted,
3901
4213
  useWebWorkers: getOptionValue$1(zipEntry, options, OPTION_USE_WEB_WORKERS),
3902
4214
  useCompressionStream,
3903
4215
  transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
@@ -3911,6 +4223,7 @@ let ZipEntry$1 = class ZipEntry {
3911
4223
  await detectOverlappingEntry({
3912
4224
  reader,
3913
4225
  fileEntry,
4226
+ index,
3914
4227
  offset,
3915
4228
  diskNumberStart,
3916
4229
  signature,
@@ -4013,7 +4326,7 @@ function readCommonFooter(fileEntry, directory, dataView, offset, localDirectory
4013
4326
  directory.extraFieldUnicodeComment = extraFieldUnicodeComment;
4014
4327
  }
4015
4328
  const extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES);
4016
- if (extraFieldAES) {
4329
+ if (extraFieldAES && extraFieldAES.data.length >= 7) {
4017
4330
  readExtraFieldAES(extraFieldAES, directory, compressionMethod);
4018
4331
  directory.extraFieldAES = extraFieldAES;
4019
4332
  } else {
@@ -4050,19 +4363,23 @@ function readExtraFieldZip64(extraFieldZip64, directory) {
4050
4363
  directory.zip64 = true;
4051
4364
  const extraFieldView = getDataView$1(extraFieldZip64.data);
4052
4365
  const missingProperties = ZIP64_PROPERTIES.filter(([propertyName, max]) => directory[propertyName] == max);
4366
+ const requiredLength = missingProperties.reduce((length, [, max]) => length + ZIP64_EXTRACTION[max].bytes, 0);
4367
+ if (extraFieldZip64.data.length < requiredLength) {
4368
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4369
+ }
4053
4370
  for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
4054
4371
  const [propertyName, max] = missingProperties[indexMissingProperty];
4055
- if (directory[propertyName] == max) {
4056
- const extraction = ZIP64_EXTRACTION[max];
4057
- directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4058
- offset += extraction.bytes;
4059
- } else if (extraFieldZip64[propertyName]) {
4060
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4061
- }
4372
+ const extraction = ZIP64_EXTRACTION[max];
4373
+ directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4374
+ offset += extraction.bytes;
4062
4375
  }
4063
4376
  }
4064
4377
 
4065
4378
  function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) {
4379
+ if (extraFieldUnicode.data.length < 5) {
4380
+ extraFieldUnicode.valid = false;
4381
+ return;
4382
+ }
4066
4383
  const extraFieldView = getDataView$1(extraFieldUnicode.data);
4067
4384
  const crc32 = new Crc32();
4068
4385
  crc32.append(fileEntry[rawPropertyName]);
@@ -4135,32 +4452,30 @@ function readExtraFieldNTFS(extraFieldNTFS, directory) {
4135
4452
  function readExtraFieldUnix(extraField, directory, isInfoZip) {
4136
4453
  try {
4137
4454
  const view = getDataView$1(new Uint8Array(extraField.data));
4138
- let offset = 0;
4139
- const version = getUint8(view, offset++);
4140
- const uidSize = getUint8(view, offset++);
4141
- const uidBytes = extraField.data.subarray(offset, offset + uidSize);
4142
- offset += uidSize;
4143
- const uid = unpackUnixId(uidBytes);
4144
- const gidSize = getUint8(view, offset++);
4145
- const gidBytes = extraField.data.subarray(offset, offset + gidSize);
4146
- offset += gidSize;
4147
- const gid = unpackUnixId(gidBytes);
4148
- let unixMode = UNDEFINED_VALUE;
4149
- if (!isInfoZip && offset + 2 <= extraField.data.length) {
4150
- const base = extraField.data;
4151
- const modeView = new DataView(base.buffer, base.byteOffset + offset, 2);
4152
- unixMode = modeView.getUint16(0, true);
4153
- }
4154
- Object.assign(extraField, { version, uid, gid, unixMode });
4455
+ let uid, gid;
4456
+ if (isInfoZip) {
4457
+ // Info-ZIP New Unix "ux" field (0x7875): version + variable-length uid/gid
4458
+ let offset = 0;
4459
+ const version = getUint8(view, offset++);
4460
+ const uidSize = getUint8(view, offset++);
4461
+ uid = unpackUnixId(extraField.data.subarray(offset, offset + uidSize));
4462
+ offset += uidSize;
4463
+ const gidSize = getUint8(view, offset++);
4464
+ gid = unpackUnixId(extraField.data.subarray(offset, offset + gidSize));
4465
+ Object.assign(extraField, { version, uid, gid });
4466
+ } else if (extraField.data.length >= 4) {
4467
+ // Info-ZIP Unix "Ux" field (0x7855): fixed 2-byte uid + gid (the file mode, if any, is
4468
+ // carried in the external file attributes, not here)
4469
+ uid = getUint16(view, 0);
4470
+ gid = getUint16(view, 2);
4471
+ Object.assign(extraField, { uid, gid });
4472
+ }
4155
4473
  if (uid !== UNDEFINED_VALUE) {
4156
4474
  directory.uid = uid;
4157
4475
  }
4158
4476
  if (gid !== UNDEFINED_VALUE) {
4159
4477
  directory.gid = gid;
4160
4478
  }
4161
- if (unixMode !== UNDEFINED_VALUE) {
4162
- directory.unixMode = unixMode;
4163
- }
4164
4479
  } catch {
4165
4480
  // ignored
4166
4481
  }
@@ -4174,6 +4489,9 @@ function unpackUnixId(bytes) {
4174
4489
  }
4175
4490
 
4176
4491
  function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory) {
4492
+ if (!extraFieldExtendedTimestamp.data.length) {
4493
+ return;
4494
+ }
4177
4495
  const extraFieldView = getDataView$1(extraFieldExtendedTimestamp.data);
4178
4496
  const flags = getUint8(extraFieldView, 0);
4179
4497
  const timeProperties = [];
@@ -4199,7 +4517,8 @@ function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory,
4199
4517
  timeProperties.forEach((propertyName, indexProperty) => {
4200
4518
  if (extraFieldExtendedTimestamp.data.length >= offset + 4) {
4201
4519
  const time = getUint32(extraFieldView, offset);
4202
- directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date(time * 1000);
4520
+ // the extended timestamp is a signed 32-bit time_t value
4521
+ directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date((time | 0) * 1000);
4203
4522
  const rawPropertyName = timeRawProperties[indexProperty];
4204
4523
  extraFieldExtendedTimestamp[rawPropertyName] = time;
4205
4524
  }
@@ -4210,6 +4529,7 @@ function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory,
4210
4529
  async function detectOverlappingEntry({
4211
4530
  reader,
4212
4531
  fileEntry,
4532
+ index,
4213
4533
  offset,
4214
4534
  diskNumberStart,
4215
4535
  signature,
@@ -4221,10 +4541,9 @@ async function detectOverlappingEntry({
4221
4541
  readRanges
4222
4542
  }) {
4223
4543
  let diskOffset = 0;
4224
- if (diskNumberStart) {
4225
- for (let indexReader = 0; indexReader < diskNumberStart; indexReader++) {
4226
- const diskReader = reader.readers[indexReader];
4227
- diskOffset += diskReader.size;
4544
+ if (diskNumberStart && reader.readers) {
4545
+ for (let indexReader = 0; indexReader < Math.min(diskNumberStart, reader.readers.length); indexReader++) {
4546
+ diskOffset += reader.readers[indexReader].size;
4228
4547
  }
4229
4548
  }
4230
4549
  let dataDescriptorLength = 0;
@@ -4237,7 +4556,8 @@ async function detectOverlappingEntry({
4237
4556
  }
4238
4557
  if (dataDescriptorLength) {
4239
4558
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, diskNumberStart);
4240
- const dataDescriptorSignature = getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4559
+ const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
4560
+ getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4241
4561
  if (dataDescriptorSignature) {
4242
4562
  const readSignature = getUint32(getDataView$1(dataDescriptorArray), 4);
4243
4563
  let readCompressedSize;
@@ -4262,14 +4582,14 @@ async function detectOverlappingEntry({
4262
4582
  end: diskOffset + dataOffset + compressedSize + dataDescriptorLength,
4263
4583
  fileEntry
4264
4584
  };
4265
- for (const otherRange of readRanges) {
4266
- if (otherRange.fileEntry != fileEntry && range.start >= otherRange.start && range.start < otherRange.end) {
4585
+ for (const [otherIndex, otherRange] of readRanges) {
4586
+ if (otherIndex != index && range.start < otherRange.end && otherRange.start < range.end) {
4267
4587
  const error = new Error(ERR_OVERLAPPING_ENTRY);
4268
4588
  error.overlappingEntry = otherRange.fileEntry;
4269
4589
  throw error;
4270
4590
  }
4271
4591
  }
4272
- readRanges.push(range);
4592
+ readRanges.set(index, range);
4273
4593
  }
4274
4594
 
4275
4595
  async function seekSignature(reader, signature, startOffset, minimumBytes, maximumLength) {
@@ -4294,6 +4614,35 @@ async function seekSignature(reader, signature, startOffset, minimumBytes, maxim
4294
4614
  }
4295
4615
  }
4296
4616
 
4617
+ function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
4618
+ const { rawFilename } = zipEntry;
4619
+ if (rawLocalFilename.length != rawFilename.length ||
4620
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
4621
+ throwAmbiguousArchive("mismatched local file header (filename)");
4622
+ }
4623
+ if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
4624
+ throwAmbiguousArchive("mismatched local file header (general purpose bit flag)");
4625
+ }
4626
+ if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
4627
+ throwAmbiguousArchive("mismatched local file header (compression method)");
4628
+ }
4629
+ // when the data descriptor flag is set, the local signature and sizes are zeroed out; all-zero values are
4630
+ // also tolerated when the flag is clear because some tools produce them (streaming writers predating bit 3)
4631
+ if (!localDirectory.bitFlag.dataDescriptor &&
4632
+ (localDirectory.signature || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
4633
+ (localDirectory.signature != zipEntry.signature ||
4634
+ localDirectory.compressedSize != zipEntry.compressedSize ||
4635
+ localDirectory.uncompressedSize != zipEntry.uncompressedSize)) {
4636
+ throwAmbiguousArchive("mismatched local file header (signature or sizes)");
4637
+ }
4638
+ }
4639
+
4640
+ function throwAmbiguousArchive(reason) {
4641
+ const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
4642
+ error.reason = reason;
4643
+ throw error;
4644
+ }
4645
+
4297
4646
  function getOptionValue$1(zipReader, options, name) {
4298
4647
  return options[name] === UNDEFINED_VALUE ? zipReader.options[name] : options[name];
4299
4648
  }
@@ -4332,7 +4681,7 @@ function setUint32$1(view, offset, value) {
4332
4681
  }
4333
4682
 
4334
4683
  function getDataView$1(array) {
4335
- return new DataView(array.buffer);
4684
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
4336
4685
  }
4337
4686
 
4338
4687
  /*
@@ -4372,13 +4721,19 @@ const ERR_INVALID_VERSION = "Version exceeds 65535";
4372
4721
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
4373
4722
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
4374
4723
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
4724
+ // same message as the constant exported by zip-reader.js
4725
+ const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
4726
+ const MIN_UNIX_TIME = -2147483648;
4727
+ const MAX_UNIX_TIME = 2147483647;
4375
4728
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
4376
4729
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
4730
+ const ERR_UNDEFINED_READER = "Undefined reader";
4377
4731
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
4378
4732
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
4379
4733
  const ERR_INVALID_GID = "Invalid gid (must be integer 0..2^32-1)";
4380
4734
  const ERR_INVALID_UNIX_MODE = "Invalid UNIX mode (must be integer 0..65535)";
4381
4735
  const ERR_INVALID_UNIX_EXTRA_FIELD_TYPE = "Invalid unixExtraFieldType (must be 'infozip' or 'unix')";
4736
+ const ERR_INVALID_UNIX_ID_SIZE = "uid/gid must be 0..65535 for unixExtraFieldType 'unix' (use 'infozip' for larger ids)";
4382
4737
  const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be integer 0..255)";
4383
4738
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
4384
4739
 
@@ -4404,9 +4759,10 @@ class ZipWriter {
4404
4759
  files: new Map(),
4405
4760
  filenames: new Set(),
4406
4761
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
4407
- pendingEntriesSize: 0,
4762
+ initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
4408
4763
  pendingAddFileCalls: new Set(),
4409
- bufferedWrites: 0
4764
+ bufferedWrites: 0,
4765
+ lastFileEntry: UNDEFINED_VALUE
4410
4766
  });
4411
4767
  }
4412
4768
 
@@ -4415,17 +4771,18 @@ class ZipWriter {
4415
4771
  throw new Error(ERR_ZIP_NOT_EMPTY);
4416
4772
  }
4417
4773
  reader = new GenericReader(reader);
4774
+ await initStream(reader);
4418
4775
  const zipReader = new ZipReader(reader.readable);
4419
4776
  const entries = await zipReader.getEntries();
4420
4777
  await zipReader.close();
4778
+ await initStream(this.writer);
4421
4779
  await reader.readable.pipeTo(this.writer.writable, { preventClose: true, preventAbort: true });
4422
4780
  this.writer.size = this.offset = reader.size;
4423
4781
  this.filenames = new Set(entries.map(entry => entry.filename));
4424
4782
  this.files = new Map(entries.map(entry => {
4425
4783
  const {
4426
4784
  version,
4427
- compressionMethod,
4428
- lastModDate,
4785
+ rawLastModDate,
4429
4786
  lastAccessDate,
4430
4787
  creationDate,
4431
4788
  rawFilename,
@@ -4438,6 +4795,7 @@ class ZipWriter {
4438
4795
  zip64
4439
4796
  } = entry;
4440
4797
  let {
4798
+ compressionMethod,
4441
4799
  rawExtraFieldZip64,
4442
4800
  rawExtraFieldAES,
4443
4801
  rawExtraFieldExtendedTimestamp,
@@ -4450,31 +4808,39 @@ class ZipWriter {
4450
4808
  rawExtraFieldAES = rawExtraFieldAES || new Uint8Array();
4451
4809
  rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || new Uint8Array();
4452
4810
  rawExtraFieldNTFS = rawExtraFieldNTFS || new Uint8Array();
4453
- rawExtraFieldUnix = entry.rawExtraFieldUnix || new Uint8Array();
4811
+ rawExtraFieldUnix = rawExtraFieldUnix || new Uint8Array();
4454
4812
  rawExtraField = rawExtraField || new Uint8Array();
4813
+ if (entry.extraFieldAES) {
4814
+ compressionMethod = COMPRESSION_METHOD_AES;
4815
+ }
4455
4816
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
4456
- const zip64UncompressedSize = zip64 && uncompressedSize > MAX_32_BITS;
4457
- const zip64CompressedSize = zip64 && compressedSize > MAX_32_BITS;
4817
+ const zip64UncompressedSize = zip64 && uncompressedSize >= MAX_32_BITS;
4818
+ const zip64CompressedSize = zip64 && compressedSize >= MAX_32_BITS;
4819
+ const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
4458
4820
  const {
4459
4821
  headerArray,
4460
4822
  headerView
4461
4823
  } = getHeaderArrayData({
4462
4824
  version,
4463
- bitFlag: getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod),
4825
+ bitFlag: bitFlagValue,
4464
4826
  compressionMethod,
4465
4827
  uncompressedSize,
4466
4828
  compressedSize,
4467
- lastModDate,
4829
+ rawLastModDate,
4468
4830
  rawFilename,
4469
4831
  zip64CompressedSize,
4470
4832
  zip64UncompressedSize,
4471
4833
  extraFieldLength
4472
4834
  });
4835
+ const { signature } = entry;
4836
+ if (signature !== UNDEFINED_VALUE) {
4837
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, signature);
4838
+ }
4473
4839
  Object.assign(entry, {
4474
4840
  zip64UncompressedSize,
4475
4841
  zip64CompressedSize,
4476
- zip64Offset: zip64 && this.offset - diskOffset > MAX_32_BITS,
4477
- zip64DiskNumberStart: zip64 && diskNumber > MAX_16_BITS,
4842
+ zip64Offset: zip64 && this.offset - diskOffset >= MAX_32_BITS,
4843
+ zip64DiskNumberStart: zip64 && diskNumber >= MAX_16_BITS,
4478
4844
  rawExtraFieldZip64,
4479
4845
  rawExtraFieldAES,
4480
4846
  rawExtraFieldExtendedTimestamp,
@@ -4492,6 +4858,7 @@ class ZipWriter {
4492
4858
 
4493
4859
  async add(name = "", reader, options = {}) {
4494
4860
  const zipWriter = this;
4861
+ options = Object.assign({}, options);
4495
4862
  const {
4496
4863
  pendingAddFileCalls,
4497
4864
  config
@@ -4502,17 +4869,24 @@ class ZipWriter {
4502
4869
  await new Promise(resolve => pendingEntries.push(resolve));
4503
4870
  }
4504
4871
  let promiseAddFile;
4872
+ let nameAdded;
4505
4873
  try {
4506
4874
  name = name.trim();
4875
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
4876
+ name += DIRECTORY_SIGNATURE;
4877
+ }
4507
4878
  if (zipWriter.filenames.has(name)) {
4508
4879
  throw new Error(ERR_DUPLICATED_NAME);
4509
4880
  }
4510
4881
  zipWriter.filenames.add(name);
4882
+ nameAdded = true;
4511
4883
  promiseAddFile = addFile(zipWriter, name, reader, options);
4512
4884
  pendingAddFileCalls.add(promiseAddFile);
4513
4885
  return await promiseAddFile;
4514
4886
  } catch (error) {
4515
- zipWriter.filenames.delete(name);
4887
+ if (nameAdded) {
4888
+ zipWriter.filenames.delete(name);
4889
+ }
4516
4890
  throw error;
4517
4891
  } finally {
4518
4892
  pendingAddFileCalls.delete(promiseAddFile);
@@ -4545,6 +4919,9 @@ class ZipWriter {
4545
4919
  const zipWriter = this;
4546
4920
  const { pendingAddFileCalls, writer } = this;
4547
4921
  const { writable } = writer;
4922
+ if (getLength(comment) > MAX_16_BITS) {
4923
+ throw new Error(ERR_INVALID_COMMENT);
4924
+ }
4548
4925
  while (pendingAddFileCalls.size) {
4549
4926
  await Promise.allSettled(Array.from(pendingAddFileCalls));
4550
4927
  }
@@ -4563,28 +4940,94 @@ class ZipWriterStream {
4563
4940
  const { readable, writable } = new TransformStream();
4564
4941
  this.readable = readable;
4565
4942
  this.zipWriter = new ZipWriter(writable, options);
4943
+ this.pendingAddFileCalls = new Set();
4566
4944
  }
4567
4945
 
4568
4946
  transform(path) {
4947
+ const zipWriter = this.zipWriter;
4948
+ let streamController;
4569
4949
  const { readable, writable } = new TransformStream({
4570
- flush: () => { this.zipWriter.close(); }
4950
+ start(controller) {
4951
+ streamController = controller;
4952
+ },
4953
+ flush: () => void closeArchive()
4571
4954
  });
4572
- this.zipWriter.add(path, readable);
4955
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4573
4956
  return { readable: this.readable, writable };
4957
+
4958
+ async function closeArchive() {
4959
+ try {
4960
+ await zipWriter.close();
4961
+ } catch (error) {
4962
+ try {
4963
+ await zipWriter.writer.writable.abort(error);
4964
+ } catch {
4965
+ // ignored
4966
+ }
4967
+ }
4968
+ }
4574
4969
  }
4575
4970
 
4576
4971
  writable(path) {
4577
- const { readable, writable } = new TransformStream();
4578
- this.zipWriter.add(path, readable);
4972
+ let streamController;
4973
+ const { readable, writable } = new TransformStream({
4974
+ start(controller) {
4975
+ streamController = controller;
4976
+ }
4977
+ });
4978
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4579
4979
  return writable;
4580
4980
  }
4581
4981
 
4582
- close(comment = UNDEFINED_VALUE, options = {}) {
4982
+ async close(comment = UNDEFINED_VALUE, options = {}) {
4983
+ await Promise.all(Array.from(this.pendingAddFileCalls));
4583
4984
  return this.zipWriter.close(comment, options);
4584
4985
  }
4585
4986
  }
4586
4987
 
4988
+ function watchAddFileCall(zipWriterStream, promiseAddFile, onerror) {
4989
+ zipWriterStream.pendingAddFileCalls.add(promiseAddFile);
4990
+ promiseAddFile.catch(error => {
4991
+ try {
4992
+ onerror(error);
4993
+ } catch {
4994
+ // ignored
4995
+ }
4996
+ });
4997
+ }
4998
+
4587
4999
  async function addFile(zipWriter, name, reader, options) {
5000
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
5001
+ ({ name } = attributesInfo);
5002
+ const metadataInfo = resolveMetadata(zipWriter, name, options);
5003
+ const { comment } = metadataInfo;
5004
+ const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
5005
+ zipWriter.files.set(name, UNDEFINED_VALUE);
5006
+ let fileEntry;
5007
+ try {
5008
+ const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
5009
+ ({ reader } = sizesInfo);
5010
+ const { diskOffset, diskNumber } = zipWriter.writer;
5011
+ options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
5012
+ internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
5013
+ externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
5014
+ signature: options[PROPERTY_NAME_SIGNATURE],
5015
+ offset: zipWriter.offset - diskOffset,
5016
+ diskNumberStart: diskNumber
5017
+ });
5018
+ const headerInfo = getHeaderInfo(options);
5019
+ const dataDescriptorInfo = getDataDescriptorInfo(options);
5020
+ const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
5021
+ fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
5022
+ } catch (error) {
5023
+ zipWriter.files.delete(name);
5024
+ throw error;
5025
+ }
5026
+ Object.assign(fileEntry, { name, comment, extraField });
5027
+ return new Entry(fileEntry);
5028
+ }
5029
+
5030
+ function resolveAttributes(zipWriter, name, options) {
4588
5031
  name = name.trim();
4589
5032
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
4590
5033
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
@@ -4592,7 +5035,7 @@ async function addFile(zipWriter, name, reader, options) {
4592
5035
  const uid = getOptionValue(zipWriter, options, PROPERTY_NAME_UID);
4593
5036
  const gid = getOptionValue(zipWriter, options, PROPERTY_NAME_GID);
4594
5037
  let unixMode = getOptionValue(zipWriter, options, PROPERTY_NAME_UNIX_MODE);
4595
- const unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
5038
+ let unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
4596
5039
  let setuid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETUID);
4597
5040
  let setgid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETGID);
4598
5041
  let sticky = getOptionValue(zipWriter, options, PROPERTY_NAME_STICKY);
@@ -4608,6 +5051,13 @@ async function addFile(zipWriter, name, reader, options) {
4608
5051
  if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
4609
5052
  throw new Error(ERR_INVALID_UNIX_EXTRA_FIELD_TYPE);
4610
5053
  }
5054
+ if (unixExtraFieldType === UNIX_EXTRA_FIELD_TYPE &&
5055
+ ((uid !== UNDEFINED_VALUE && uid > MAX_16_BITS) || (gid !== UNDEFINED_VALUE && gid > MAX_16_BITS))) {
5056
+ throw new Error(ERR_INVALID_UNIX_ID_SIZE);
5057
+ }
5058
+ if (unixExtraFieldType === UNDEFINED_VALUE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5059
+ unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE;
5060
+ }
4611
5061
  let msdosAttributesRaw = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW);
4612
5062
  let msdosAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES);
4613
5063
  const hasUnixMetadata = uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE || unixExtraFieldType;
@@ -4678,6 +5128,27 @@ async function addFile(zipWriter, name, reader, options) {
4678
5128
  if (hasMsDosProvided) {
4679
5129
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
4680
5130
  }
5131
+ return {
5132
+ name,
5133
+ resolvedOptions: {
5134
+ versionMadeBy,
5135
+ msDosCompatible,
5136
+ externalFileAttributes,
5137
+ unixExternalUpper,
5138
+ uid,
5139
+ gid,
5140
+ unixMode,
5141
+ unixExtraFieldType,
5142
+ setuid,
5143
+ setgid,
5144
+ sticky,
5145
+ msdosAttributesRaw,
5146
+ msdosAttributes
5147
+ }
5148
+ };
5149
+ }
5150
+
5151
+ function resolveMetadata(zipWriter, name, options) {
4681
5152
  const encode = getOptionValue(zipWriter, options, OPTION_ENCODE_TEXT, encodeText);
4682
5153
  let rawFilename = encode(name);
4683
5154
  if (rawFilename === UNDEFINED_VALUE) {
@@ -4716,10 +5187,14 @@ async function addFile(zipWriter, name, reader, options) {
4716
5187
  const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS, true);
4717
5188
  const bufferedWrite = getOptionValue(zipWriter, options, OPTION_BUFFERED_WRITE);
4718
5189
  const createTempStream = getOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
4719
- const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, false);
5190
+ const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
4720
5191
  const signal = getOptionValue(zipWriter, options, OPTION_SIGNAL);
4721
5192
  const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
4722
5193
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
5194
+ if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
5195
+ compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE) {
5196
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5197
+ }
4723
5198
  let level = getOptionValue(zipWriter, options, OPTION_LEVEL);
4724
5199
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
4725
5200
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
@@ -4735,7 +5210,7 @@ async function addFile(zipWriter, name, reader, options) {
4735
5210
  if (!useCompressionStream && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
4736
5211
  level = 0;
4737
5212
  }
4738
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5213
+ const zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
4739
5214
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
4740
5215
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
4741
5216
  }
@@ -4746,6 +5221,7 @@ async function addFile(zipWriter, name, reader, options) {
4746
5221
  let offset = 0;
4747
5222
  extraField.forEach(data => extraFieldSize += 4 + getLength(data));
4748
5223
  rawExtraField = new Uint8Array(extraFieldSize);
5224
+ const rawExtraFieldView = getDataView(rawExtraField);
4749
5225
  extraField.forEach((data, type) => {
4750
5226
  if (type > MAX_16_BITS) {
4751
5227
  throw new Error(ERR_INVALID_EXTRAFIELD_TYPE);
@@ -4753,22 +5229,72 @@ async function addFile(zipWriter, name, reader, options) {
4753
5229
  if (getLength(data) > MAX_16_BITS) {
4754
5230
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
4755
5231
  }
4756
- arraySet(rawExtraField, new Uint16Array([type]), offset);
4757
- arraySet(rawExtraField, new Uint16Array([getLength(data)]), offset + 2);
5232
+ setUint16(rawExtraFieldView, offset, type);
5233
+ setUint16(rawExtraFieldView, offset + 2, getLength(data));
4758
5234
  arraySet(rawExtraField, data, offset + 4);
4759
5235
  offset += 4 + getLength(data);
4760
5236
  });
4761
5237
  }
5238
+ return {
5239
+ comment,
5240
+ resolvedOptions: {
5241
+ rawFilename,
5242
+ rawComment,
5243
+ version,
5244
+ lastModDate,
5245
+ lastAccessDate,
5246
+ creationDate,
5247
+ internalFileAttributes,
5248
+ passThrough,
5249
+ password,
5250
+ rawPassword,
5251
+ encryptionStrength,
5252
+ zipCrypto,
5253
+ extendedTimestamp,
5254
+ keepOrder,
5255
+ useWebWorkers,
5256
+ transferStreams,
5257
+ bufferedWrite,
5258
+ createTempStream,
5259
+ dataDescriptorSignature,
5260
+ signal,
5261
+ useUnicodeFileNames,
5262
+ compressionMethod,
5263
+ level,
5264
+ useCompressionStream,
5265
+ dataDescriptor,
5266
+ zip64,
5267
+ rawExtraField
5268
+ }
5269
+ };
5270
+ }
5271
+
5272
+ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
5273
+ const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
5274
+ let { dataDescriptor, zip64, level, compressionMethod } = metadata;
4762
5275
  let maximumCompressedSize = 0;
4763
- let maximumEntrySize = 0;
4764
5276
  let uncompressedSize = 0;
4765
5277
  if (passThrough) {
5278
+ // the headers of a passThrough entry describe the payload verbatim: without a
5279
+ // reader they would declare content that is not there
5280
+ if (!reader) {
5281
+ throw new Error(ERR_UNDEFINED_READER);
5282
+ }
4766
5283
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
4767
5284
  if (uncompressedSize === UNDEFINED_VALUE) {
4768
5285
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
4769
5286
  }
4770
5287
  }
4771
5288
  const zip64Enabled = zip64 === true;
5289
+ const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
5290
+ // entries without a reader have no payload: write them as empty stored files instead of
5291
+ // declaring a compressed or encrypted content that does not exist
5292
+ const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
5293
+ if (!reader) {
5294
+ level = 0;
5295
+ compressionMethod = COMPRESSION_METHOD_STORE;
5296
+ }
5297
+ const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4772
5298
  if (reader) {
4773
5299
  reader = new GenericReader(reader);
4774
5300
  await initStream(reader);
@@ -4781,16 +5307,15 @@ async function addFile(zipWriter, name, reader, options) {
4781
5307
  }
4782
5308
  } else {
4783
5309
  options.uncompressedSize = uncompressedSize = reader.size;
4784
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5310
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4785
5311
  }
4786
5312
  } else {
4787
5313
  options.uncompressedSize = uncompressedSize;
4788
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5314
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4789
5315
  }
4790
5316
  }
4791
- const { diskOffset, diskNumber } = zipWriter.writer;
4792
- const zip64UncompressedSize = zip64Enabled || uncompressedSize > MAX_32_BITS;
4793
- const zip64CompressedSize = zip64Enabled || maximumCompressedSize > MAX_32_BITS;
5317
+ const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
5318
+ const zip64CompressedSize = zip64Enabled || maximumCompressedSize >= MAX_32_BITS;
4794
5319
  if (zip64UncompressedSize || zip64CompressedSize) {
4795
5320
  if (zip64 === false) {
4796
5321
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -4799,73 +5324,19 @@ async function addFile(zipWriter, name, reader, options) {
4799
5324
  }
4800
5325
  }
4801
5326
  zip64 = zip64 || false;
4802
- const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
4803
- options = Object.assign({}, options, {
4804
- rawFilename,
4805
- rawComment,
4806
- version,
4807
- versionMadeBy,
4808
- lastModDate,
4809
- lastAccessDate,
4810
- creationDate,
4811
- rawExtraField,
4812
- zip64,
4813
- zip64UncompressedSize,
4814
- zip64CompressedSize,
4815
- password,
4816
- rawPassword,
4817
- level,
4818
- useWebWorkers,
4819
- transferStreams,
4820
- encryptionStrength,
4821
- extendedTimestamp,
4822
- zipCrypto,
4823
- bufferedWrite,
4824
- createTempStream,
4825
- keepOrder,
4826
- useUnicodeFileNames,
4827
- dataDescriptor,
4828
- dataDescriptorSignature,
4829
- signal,
4830
- msDosCompatible,
4831
- internalFileAttribute: internalFileAttributes,
4832
- internalFileAttributes,
4833
- externalFileAttribute: externalFileAttributes,
4834
- externalFileAttributes,
4835
- useCompressionStream,
4836
- passThrough,
4837
- encrypted: Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted),
4838
- signature: options[PROPERTY_NAME_SIGNATURE],
4839
- compressionMethod,
4840
- uncompressedSize,
4841
- offset: zipWriter.offset - diskOffset,
4842
- diskNumberStart: diskNumber,
4843
- uid,
4844
- gid,
4845
- setuid,
4846
- setgid,
4847
- sticky,
4848
- unixMode,
4849
- msdosAttributesRaw,
4850
- msdosAttributes,
4851
- unixExternalUpper
4852
- });
4853
- const headerInfo = getHeaderInfo(options);
4854
- const dataDescriptorInfo = getDataDescriptorInfo(options);
4855
- const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
4856
- maximumEntrySize = metadataSize + maximumCompressedSize;
4857
- if (zipWriter.options[OPTION_USDZ]) {
4858
- maximumEntrySize += maximumEntrySize + 64;
4859
- }
4860
- zipWriter.pendingEntriesSize += maximumEntrySize;
4861
- let fileEntry;
4862
- try {
4863
- fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
4864
- } finally {
4865
- zipWriter.pendingEntriesSize -= maximumEntrySize;
4866
- }
4867
- Object.assign(fileEntry, { name, comment, extraField });
4868
- return new Entry(fileEntry);
5327
+ return {
5328
+ reader,
5329
+ resolvedOptions: {
5330
+ dataDescriptor,
5331
+ zip64,
5332
+ zip64UncompressedSize,
5333
+ zip64CompressedSize,
5334
+ uncompressedSize,
5335
+ level,
5336
+ compressionMethod,
5337
+ encrypted: encryptedEntry
5338
+ }
5339
+ };
4869
5340
  }
4870
5341
 
4871
5342
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
@@ -4882,37 +5353,40 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4882
5353
  headerInfo
4883
5354
  } = entryInfo;
4884
5355
  const usdz = zipWriter.options[OPTION_USDZ];
4885
- const previousFileEntry = Array.from(files.values()).pop();
5356
+ const previousFileEntry = zipWriter.lastFileEntry;
4886
5357
  let fileEntry = {};
4887
5358
  let bufferedWrite;
4888
5359
  let releaseLockWriter;
4889
5360
  let releaseLockCurrentFileEntry;
4890
5361
  let writingBufferedEntryData;
4891
5362
  let writingEntryData;
5363
+ let writerSizeBeforeEntry;
5364
+ let flushedBufferedSize = 0;
4892
5365
  let fileWriter;
4893
5366
  files.set(name, fileEntry);
5367
+ zipWriter.lastFileEntry = fileEntry;
4894
5368
  try {
4895
5369
  let lockPreviousFileEntry;
4896
5370
  if (keepOrder) {
4897
5371
  lockPreviousFileEntry = previousFileEntry && previousFileEntry.lock;
4898
5372
  requestLockCurrentFileEntry();
4899
5373
  }
4900
- if ((options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) && !usdz) {
5374
+ if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) {
5375
+ bufferedWrite = true;
5376
+ zipWriter.bufferedWrites++;
4901
5377
  if (options.createTempStream) {
4902
5378
  fileWriter = await options.createTempStream();
4903
5379
  } else {
4904
5380
  fileWriter = new TransformStream(UNDEFINED_VALUE, UNDEFINED_VALUE, { highWaterMark: INFINITY_VALUE });
4905
5381
  }
4906
5382
  fileWriter.size = 0;
4907
- bufferedWrite = true;
4908
- zipWriter.bufferedWrites++;
4909
5383
  await initStream(writer);
4910
5384
  } else {
4911
5385
  fileWriter = writer;
4912
5386
  await requestLockWriter();
4913
5387
  }
4914
5388
  await initStream(fileWriter);
4915
- const { writable, diskOffset } = writer;
5389
+ const { diskOffset } = writer;
4916
5390
  if (zipWriter.addSplitZipSignature) {
4917
5391
  delete zipWriter.addSplitZipSignature;
4918
5392
  const signatureArray = new Uint8Array(4);
@@ -4921,21 +5395,20 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4921
5395
  await writeData(writer, signatureArray);
4922
5396
  zipWriter.offset += 4;
4923
5397
  }
4924
- if (usdz) {
5398
+ if (usdz && !bufferedWrite) {
4925
5399
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
4926
5400
  }
4927
- const {
4928
- localHeaderView,
4929
- localHeaderArray
4930
- } = headerInfo;
5401
+ const { localHeaderArray } = headerInfo;
4931
5402
  if (!bufferedWrite) {
4932
5403
  await lockPreviousFileEntry;
4933
- await skipDiskIfNeeded(writable);
5404
+ await skipDiskIfNeeded();
4934
5405
  }
4935
- const { diskNumber } = writer;
4936
- fileEntry.diskNumberStart = diskNumber;
5406
+ const diskNumberStart = writer.diskNumber;
5407
+ const entryOffset = getSegmentOffset(zipWriter, writer);
5408
+ fileEntry.diskNumberStart = diskNumberStart;
4937
5409
  if (!bufferedWrite) {
4938
5410
  writingEntryData = true;
5411
+ writerSizeBeforeEntry = writer.size;
4939
5412
  await writeData(fileWriter, localHeaderArray);
4940
5413
  }
4941
5414
  fileEntry = await createFileEntry(reader, fileWriter, fileEntry, entryInfo, zipWriter.config, options);
@@ -4948,16 +5421,24 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4948
5421
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
4949
5422
  await requestLockWriter();
4950
5423
  writingBufferedEntryData = true;
5424
+ writerSizeBeforeEntry = writer.size;
5425
+ await skipDiskIfNeeded();
4951
5426
  fileEntry.diskNumberStart = writer.diskNumber;
4952
- fileEntry.offset = zipWriter.offset - writer.diskOffset;
4953
- updateLocalHeader(fileEntry, localHeaderView, options);
4954
- await skipDiskIfNeeded(writable);
4955
- await writeData(writer, localHeaderArray);
4956
- await fileWriter.readable.pipeTo(writable, { preventClose: true, preventAbort: true, signal });
5427
+ fileEntry.offset = getSegmentOffset(zipWriter, writer);
5428
+ if (usdz) {
5429
+ // the padding depends on the entry offset, only known now that the writer is locked
5430
+ const previousMetadataSize = entryInfo.metadataSize;
5431
+ appendExtraFieldUSDZ(entryInfo, zipWriter.offset - writer.diskOffset);
5432
+ fileEntry.size += entryInfo.metadataSize - previousMetadataSize;
5433
+ }
5434
+ updateLocalHeader(fileEntry, headerInfo.localHeaderView, options);
5435
+ await writeData(writer, headerInfo.localHeaderArray);
5436
+ await flushBufferedData(fileWriter.readable, writer, signal, chunkLength => flushedBufferedSize += chunkLength);
4957
5437
  writer.size += fileWriter.size;
4958
5438
  writingBufferedEntryData = false;
4959
5439
  } else {
4960
- fileEntry.offset = zipWriter.offset - diskOffset;
5440
+ fileEntry.diskNumberStart = diskNumberStart;
5441
+ fileEntry.offset = entryOffset;
4961
5442
  }
4962
5443
  zipWriter.offset += fileEntry.size;
4963
5444
  return fileEntry;
@@ -4971,10 +5452,9 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
4971
5452
  // ignored
4972
5453
  }
4973
5454
  }
5455
+ zipWriter.offset += writer.size - writerSizeBeforeEntry;
4974
5456
  if (bufferedWrite) {
4975
- zipWriter.offset += fileWriter.size;
4976
- } else {
4977
- zipWriter.offset = fileWriter.size;
5457
+ zipWriter.offset += flushedBufferedSize;
4978
5458
  }
4979
5459
  }
4980
5460
  files.delete(name);
@@ -5005,10 +5485,10 @@ async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
5005
5485
  await lockWriter;
5006
5486
  }
5007
5487
 
5008
- async function skipDiskIfNeeded(writable) {
5488
+ async function skipDiskIfNeeded() {
5009
5489
  if (getLength(headerInfo.localHeaderArray) > writer.availableSize) {
5010
5490
  writer.availableSize = 0;
5011
- await writeData(writable, new Uint8Array());
5491
+ await writeData(writer, new Uint8Array());
5012
5492
  }
5013
5493
  }
5014
5494
  }
@@ -5149,6 +5629,10 @@ async function createFileEntry(reader, writer, { diskNumberStart, lock }, entryI
5149
5629
  uncompressedSize = result.inputSize;
5150
5630
  signature = result.signature;
5151
5631
  }
5632
+ if ((!zip64CompressedSize && compressedSize >= MAX_32_BITS) ||
5633
+ (!zip64UncompressedSize && uncompressedSize >= MAX_32_BITS)) {
5634
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
5635
+ }
5152
5636
  } catch (error) {
5153
5637
  if (error.outputSize !== UNDEFINED_VALUE) {
5154
5638
  writer.size += error.outputSize;
@@ -5211,35 +5695,28 @@ function getHeaderInfo(options) {
5211
5695
  uncompressedSize
5212
5696
  } = options;
5213
5697
  let { version, compressionMethod } = options;
5214
- const compressed = !directory && (level > 0 || (level === UNDEFINED_VALUE && compressionMethod !== 0));
5698
+ const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
5699
+ ? (level === UNDEFINED_VALUE || level > 0)
5700
+ : compressionMethod !== COMPRESSION_METHOD_STORE);
5215
5701
  let rawLocalExtraFieldZip64;
5216
5702
  const uncompressedFile = passThrough || !compressed;
5217
- const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5218
- if (zip64) {
5219
- let rawLocalExtraFieldZip64Length = 4;
5220
- if (zip64UncompressedSize) {
5221
- rawLocalExtraFieldZip64Length += 8;
5222
- }
5223
- if (zip64CompressedSize) {
5224
- rawLocalExtraFieldZip64Length += 8;
5225
- }
5226
- rawLocalExtraFieldZip64 = new Uint8Array(rawLocalExtraFieldZip64Length);
5227
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5228
- setUint16(rawLocalExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5229
- setUint16(rawLocalExtraFieldZip64View, 2, getLength(rawLocalExtraFieldZip64) - 4);
5703
+ // entries without a data descriptor are always buffered (cf. getFileEntry), so the
5704
+ // zip64 extra field values can be patched into the local header before flushing it
5705
+ const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5706
+ const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
5707
+ if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
5708
+ // APPNOTE 4.5.3: the zip64 extra field of a local header must include both the
5709
+ // uncompressed and compressed size fields
5710
+ const length = 4 + 16;
5711
+ const extraFieldZip64 = createRecordWriter(length);
5712
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
5713
+ extraFieldZip64.uint16(length - 4);
5714
+ rawLocalExtraFieldZip64 = extraFieldZip64.array;
5230
5715
  if (zip64ExtraFieldComplete) {
5231
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5232
- let rawLocalExtraFieldZip64Offset = 4;
5233
- if (zip64UncompressedSize) {
5234
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5235
- rawLocalExtraFieldZip64Offset += 8;
5236
- }
5237
- if (zip64CompressedSize && uncompressedFile) {
5238
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5239
- rawLocalExtraFieldZip64Offset += 8;
5240
- }
5241
- if (rawLocalExtraFieldZip64Offset == 4) {
5242
- rawLocalExtraFieldZip64 = new Uint8Array();
5716
+ extraFieldZip64.uint64(uncompressedSize);
5717
+ if (uncompressedFile) {
5718
+ const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
5719
+ extraFieldZip64.uint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
5243
5720
  }
5244
5721
  }
5245
5722
  } else {
@@ -5247,11 +5724,11 @@ function getHeaderInfo(options) {
5247
5724
  }
5248
5725
  let rawExtraFieldAES;
5249
5726
  if (encrypted && !zipCrypto) {
5250
- rawExtraFieldAES = new Uint8Array(getLength(EXTRAFIELD_DATA_AES) + 2);
5251
- const extraFieldAESView = getDataView(rawExtraFieldAES);
5252
- setUint16(extraFieldAESView, 0, EXTRAFIELD_TYPE_AES);
5253
- arraySet(rawExtraFieldAES, EXTRAFIELD_DATA_AES, 2);
5254
- setUint8(extraFieldAESView, 8, encryptionStrength);
5727
+ const extraFieldAES = createRecordWriter(getLength(EXTRAFIELD_DATA_AES) + 2);
5728
+ extraFieldAES.uint16(EXTRAFIELD_TYPE_AES);
5729
+ extraFieldAES.bytes(EXTRAFIELD_DATA_AES);
5730
+ rawExtraFieldAES = extraFieldAES.array;
5731
+ rawExtraFieldAES[8] = encryptionStrength;
5255
5732
  } else {
5256
5733
  rawExtraFieldAES = new Uint8Array();
5257
5734
  }
@@ -5259,33 +5736,38 @@ function getHeaderInfo(options) {
5259
5736
  let rawExtraFieldExtendedTimestamp;
5260
5737
  let extraFieldExtendedTimestampFlag;
5261
5738
  if (extendedTimestamp) {
5262
- rawExtraFieldExtendedTimestamp = new Uint8Array(9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0));
5263
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldExtendedTimestamp);
5264
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5265
- setUint16(extraFieldExtendedTimestampView, 2, getLength(rawExtraFieldExtendedTimestamp) - 4);
5266
- extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5267
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5268
- let offset = 5;
5269
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastModDate.getTime() / 1000));
5270
- offset += 4;
5271
- if (lastAccessDate) {
5272
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastAccessDate.getTime() / 1000));
5273
- offset += 4;
5274
- }
5275
- if (creationDate) {
5276
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(creationDate.getTime() / 1000));
5739
+ const lastModTimeUnix = getTimeUnix(lastModDate);
5740
+ if (inUnixTimeRange(lastModTimeUnix)) {
5741
+ const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
5742
+ const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
5743
+ extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5744
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5745
+ extraFieldTimestamp.uint16(extraFieldTimestampLength - 4);
5746
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
5747
+ extraFieldTimestamp.uint32(lastModTimeUnix);
5748
+ if (lastAccessDate) {
5749
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(lastAccessDate)));
5750
+ }
5751
+ if (creationDate) {
5752
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(creationDate)));
5753
+ }
5754
+ rawExtraFieldExtendedTimestamp = extraFieldTimestamp.array;
5755
+ } else {
5756
+ // the date cannot be stored as a 32-bit time_t; the NTFS field replaces it
5757
+ rawExtraFieldExtendedTimestamp = new Uint8Array();
5277
5758
  }
5278
5759
  try {
5279
- rawExtraFieldNTFS = new Uint8Array(36);
5280
- const extraFieldNTFSView = getDataView(rawExtraFieldNTFS);
5281
5760
  const lastModTimeNTFS = getTimeNTFS(lastModDate);
5282
- setUint16(extraFieldNTFSView, 0, EXTRAFIELD_TYPE_NTFS);
5283
- setUint16(extraFieldNTFSView, 2, 32);
5284
- setUint16(extraFieldNTFSView, 8, EXTRAFIELD_TYPE_NTFS_TAG1);
5285
- setUint16(extraFieldNTFSView, 10, 24);
5286
- setBigUint64(extraFieldNTFSView, 12, lastModTimeNTFS);
5287
- setBigUint64(extraFieldNTFSView, 20, getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5288
- setBigUint64(extraFieldNTFSView, 28, getTimeNTFS(creationDate) || lastModTimeNTFS);
5761
+ const extraFieldNTFS = createRecordWriter(36);
5762
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
5763
+ extraFieldNTFS.uint16(32);
5764
+ extraFieldNTFS.skip(4);
5765
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
5766
+ extraFieldNTFS.uint16(24);
5767
+ extraFieldNTFS.uint64(lastModTimeNTFS);
5768
+ extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5769
+ extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
5770
+ rawExtraFieldNTFS = extraFieldNTFS.array;
5289
5771
  } catch {
5290
5772
  rawExtraFieldNTFS = new Uint8Array();
5291
5773
  }
@@ -5294,41 +5776,27 @@ function getHeaderInfo(options) {
5294
5776
  }
5295
5777
  let rawExtraFieldUnix;
5296
5778
  try {
5297
- const { uid, gid, unixMode, setuid, setgid, sticky, unixExtraFieldType } = options;
5298
- if (unixExtraFieldType && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE)) {
5779
+ const { uid, gid, unixExtraFieldType } = options;
5780
+ if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5299
5781
  const uidBytes = packUnixId(uid);
5300
5782
  const gidBytes = packUnixId(gid);
5301
- let modeArray = new Uint8Array();
5302
- if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && unixMode !== UNDEFINED_VALUE) {
5303
- let modeToWrite = unixMode & MAX_16_BITS;
5304
- if (setuid) {
5305
- modeToWrite |= FILE_ATTR_UNIX_SETUID_MASK;
5306
- }
5307
- if (setgid) {
5308
- modeToWrite |= FILE_ATTR_UNIX_SETGID_MASK;
5309
- }
5310
- if (sticky) {
5311
- modeToWrite |= FILE_ATTR_UNIX_STICKY_MASK;
5312
- }
5313
- modeArray = new Uint8Array(2);
5314
- const modeDataView = new DataView(modeArray.buffer);
5315
- modeDataView.setUint16(0, modeToWrite, true);
5316
- }
5317
- const payloadLength = 3 + uidBytes.length + gidBytes.length + modeArray.length;
5318
- rawExtraFieldUnix = new Uint8Array(4 + payloadLength);
5319
- const rawExtraFieldUnixView = getDataView(rawExtraFieldUnix);
5320
- setUint16(rawExtraFieldUnixView, 0, unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE ? EXTRAFIELD_TYPE_INFOZIP : EXTRAFIELD_TYPE_UNIX);
5321
- setUint16(rawExtraFieldUnixView, 2, payloadLength);
5322
- setUint8(rawExtraFieldUnixView, 4, 1);
5323
- setUint8(rawExtraFieldUnixView, 5, uidBytes.length);
5324
- let offset = 6;
5325
- arraySet(rawExtraFieldUnix, uidBytes, offset);
5326
- offset += uidBytes.length;
5327
- setUint8(rawExtraFieldUnixView, offset, gidBytes.length);
5328
- offset++;
5329
- arraySet(rawExtraFieldUnix, gidBytes, offset);
5330
- offset += gidBytes.length;
5331
- arraySet(rawExtraFieldUnix, modeArray, offset);
5783
+ const payloadLength = 3 + uidBytes.length + gidBytes.length;
5784
+ const extraFieldUnix = createRecordWriter(4 + payloadLength);
5785
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_INFOZIP);
5786
+ extraFieldUnix.uint16(payloadLength);
5787
+ extraFieldUnix.uint8(1);
5788
+ extraFieldUnix.uint8(uidBytes.length);
5789
+ extraFieldUnix.bytes(uidBytes);
5790
+ extraFieldUnix.uint8(gidBytes.length);
5791
+ extraFieldUnix.bytes(gidBytes);
5792
+ rawExtraFieldUnix = extraFieldUnix.array;
5793
+ } else if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5794
+ const extraFieldUnix = createRecordWriter(8);
5795
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_UNIX);
5796
+ extraFieldUnix.uint16(4);
5797
+ extraFieldUnix.uint16((uid === UNDEFINED_VALUE ? 0 : uid) & MAX_16_BITS);
5798
+ extraFieldUnix.uint16((gid === UNDEFINED_VALUE ? 0 : gid) & MAX_16_BITS);
5799
+ rawExtraFieldUnix = extraFieldUnix.array;
5332
5800
  } else {
5333
5801
  rawExtraFieldUnix = new Uint8Array();
5334
5802
  }
@@ -5346,8 +5814,11 @@ function getHeaderInfo(options) {
5346
5814
  rawExtraFieldAES[9] = compressionMethod;
5347
5815
  compressionMethod = COMPRESSION_METHOD_AES;
5348
5816
  }
5349
- const localExtraFieldZip64Length = zip64ExtraFieldComplete ? getLength(rawLocalExtraFieldZip64) : 0;
5817
+ const localExtraFieldZip64Length = writeLocalExtraFieldZip64 ? getLength(rawLocalExtraFieldZip64) : 0;
5350
5818
  const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5819
+ if (extraFieldLength > MAX_16_BITS) {
5820
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
5821
+ }
5351
5822
  const {
5352
5823
  headerArray,
5353
5824
  headerView,
@@ -5363,29 +5834,27 @@ function getHeaderInfo(options) {
5363
5834
  zip64UncompressedSize,
5364
5835
  extraFieldLength
5365
5836
  });
5366
- let localHeaderOffset = HEADER_SIZE;
5367
- const localHeaderArray = new Uint8Array(localHeaderOffset + getLength(rawFilename) + extraFieldLength);
5837
+ const localHeader = createRecordWriter(HEADER_SIZE + getLength(rawFilename) + extraFieldLength);
5838
+ const localHeaderArray = localHeader.array;
5368
5839
  const localHeaderView = getDataView(localHeaderArray);
5369
- setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE);
5370
- arraySet(localHeaderArray, headerArray, 4);
5371
- arraySet(localHeaderArray, rawFilename, localHeaderOffset);
5372
- localHeaderOffset += getLength(rawFilename);
5373
- if (zip64ExtraFieldComplete) {
5374
- arraySet(localHeaderArray, rawLocalExtraFieldZip64, localHeaderOffset);
5375
- }
5376
- localHeaderOffset += localExtraFieldZip64Length;
5377
- arraySet(localHeaderArray, rawExtraFieldAES, localHeaderOffset);
5378
- localHeaderOffset += getLength(rawExtraFieldAES);
5379
- arraySet(localHeaderArray, rawExtraFieldExtendedTimestamp, localHeaderOffset);
5380
- localHeaderOffset += getLength(rawExtraFieldExtendedTimestamp);
5381
- arraySet(localHeaderArray, rawExtraFieldNTFS, localHeaderOffset);
5382
- localHeaderOffset += getLength(rawExtraFieldNTFS);
5383
- arraySet(localHeaderArray, rawExtraFieldUnix, localHeaderOffset);
5384
- localHeaderOffset += getLength(rawExtraFieldUnix);
5385
- arraySet(localHeaderArray, rawExtraField, localHeaderOffset);
5840
+ localHeader.uint32(LOCAL_FILE_HEADER_SIGNATURE);
5841
+ localHeader.bytes(headerArray);
5842
+ localHeader.bytes(rawFilename);
5843
+ if (writeLocalExtraFieldZip64) {
5844
+ localHeader.bytes(rawLocalExtraFieldZip64);
5845
+ }
5846
+ localHeader.bytes(rawExtraFieldAES);
5847
+ localHeader.bytes(rawExtraFieldExtendedTimestamp);
5848
+ localHeader.bytes(rawExtraFieldNTFS);
5849
+ localHeader.bytes(rawExtraFieldUnix);
5850
+ localHeader.bytes(rawExtraField);
5386
5851
  if (dataDescriptor) {
5387
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, 0);
5388
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, 0);
5852
+ if (!zip64CompressedSize) {
5853
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5854
+ }
5855
+ if (!zip64UncompressedSize) {
5856
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5857
+ }
5389
5858
  }
5390
5859
  return {
5391
5860
  localHeaderArray,
@@ -5412,7 +5881,7 @@ function getHeaderInfo(options) {
5412
5881
  function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
5413
5882
  const { headerInfo } = entryInfo;
5414
5883
  let { localHeaderArray, extraFieldLength } = headerInfo;
5415
- let localHeaderArrayView = getDataView(localHeaderArray);
5884
+ let localHeaderArrayView;
5416
5885
  let extraBytesLength = 64 - ((zipWriterOffset + getLength(localHeaderArray)) % 64);
5417
5886
  if (extraBytesLength < 4) {
5418
5887
  extraBytesLength += 64;
@@ -5420,13 +5889,14 @@ function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
5420
5889
  const rawExtraFieldUSDZ = new Uint8Array(extraBytesLength);
5421
5890
  const extraFieldUSDZView = getDataView(rawExtraFieldUSDZ);
5422
5891
  setUint16(extraFieldUSDZView, 0, EXTRAFIELD_TYPE_USDZ);
5423
- setUint16(extraFieldUSDZView, 2, extraBytesLength - 2);
5892
+ setUint16(extraFieldUSDZView, 2, extraBytesLength - 4);
5424
5893
  const previousLocalHeaderArray = localHeaderArray;
5425
5894
  headerInfo.localHeaderArray = localHeaderArray = new Uint8Array(getLength(previousLocalHeaderArray) + extraBytesLength);
5426
5895
  arraySet(localHeaderArray, previousLocalHeaderArray);
5427
5896
  arraySet(localHeaderArray, rawExtraFieldUSDZ, getLength(previousLocalHeaderArray));
5428
5897
  localHeaderArrayView = getDataView(localHeaderArray);
5429
5898
  setUint16(localHeaderArrayView, 28, extraFieldLength + extraBytesLength);
5899
+ headerInfo.localHeaderView = localHeaderArrayView;
5430
5900
  entryInfo.metadataSize += extraBytesLength;
5431
5901
  }
5432
5902
 
@@ -5549,37 +6019,32 @@ function updateLocalHeader({
5549
6019
  }, localHeaderView, { dataDescriptor }) {
5550
6020
  if (!dataDescriptor) {
5551
6021
  if (!encrypted) {
5552
- setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + 4, signature);
6022
+ setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, signature);
5553
6023
  }
5554
6024
  if (!zip64CompressedSize) {
5555
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, compressedSize);
6025
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, compressedSize);
5556
6026
  }
5557
6027
  if (!zip64UncompressedSize) {
5558
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, uncompressedSize);
6028
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, uncompressedSize);
5559
6029
  }
5560
6030
  }
5561
6031
  if (zip64 && localExtraFieldZip64Length) {
5562
- let localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
5563
- if (zip64UncompressedSize) {
5564
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
5565
- localHeaderOffset += 8;
5566
- }
5567
- if (zip64CompressedSize) {
5568
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(compressedSize));
5569
- localHeaderOffset += 8;
5570
- }
6032
+ // the local zip64 extra field always contains both size slots
6033
+ const localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
6034
+ setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
6035
+ setBigUint64(localHeaderView, localHeaderOffset + 8, BigInt(compressedSize));
5571
6036
  }
5572
6037
  }
5573
6038
 
5574
6039
 
5575
6040
  async function closeFile(zipWriter, comment, options) {
5576
- const { files, writer } = zipWriter;
5577
- const { diskOffset } = writer;
5578
- let { diskNumber } = writer;
5579
- let offset = 0;
6041
+ const directoryDataLength = createDirectoryRecords(zipWriter.files);
6042
+ const { cdStartDiskNumber, cdStartDiskOffset } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
6043
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { cdStartDiskNumber, cdStartDiskOffset, directoryDataLength });
6044
+ }
6045
+
6046
+ function createDirectoryRecords(files) {
5580
6047
  let directoryDataLength = 0;
5581
- let directoryOffset = zipWriter.offset - diskOffset;
5582
- let filesLength = files.size;
5583
6048
  for (const [, fileEntry] of files) {
5584
6049
  const {
5585
6050
  rawFilename,
@@ -5596,24 +6061,27 @@ async function closeFile(zipWriter, comment, options) {
5596
6061
  uncompressedSize,
5597
6062
  compressedSize
5598
6063
  } = fileEntry;
5599
- const zip64Offset = fileEntry.offset > MAX_32_BITS;
5600
- const zip64DiskNumberStart = fileEntry.diskNumberStart > MAX_16_BITS;
6064
+ const zip64Offset = fileEntry.offset >= MAX_32_BITS;
6065
+ const zip64DiskNumberStart = fileEntry.diskNumberStart >= MAX_16_BITS;
5601
6066
  let rawExtraFieldZip64;
5602
6067
  if (zip64Offset || zip64DiskNumberStart || zip64UncompressedSize || zip64CompressedSize) {
5603
- let length = 4;
5604
- if (zip64UncompressedSize) length += 8;
5605
- if (zip64CompressedSize) length += 8;
5606
- if (zip64Offset) length += 8;
5607
- if (zip64DiskNumberStart) length += 4;
5608
- rawExtraFieldZip64 = new Uint8Array(length);
5609
- const zip64View = getDataView(rawExtraFieldZip64);
5610
- setUint16(zip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5611
- setUint16(zip64View, 2, length - 4);
5612
- let zip64FieldOffset = 4;
5613
- if (zip64UncompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(uncompressedSize)); zip64FieldOffset += 8; }
5614
- if (zip64CompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(compressedSize)); zip64FieldOffset += 8; }
5615
- if (zip64Offset) { setBigUint64(zip64View, zip64FieldOffset, BigInt(fileEntry.offset)); zip64FieldOffset += 8; }
5616
- if (zip64DiskNumberStart) { setUint32(zip64View, zip64FieldOffset, fileEntry.diskNumberStart); }
6068
+ const length = 4 + (zip64UncompressedSize ? 8 : 0) + (zip64CompressedSize ? 8 : 0) + (zip64Offset ? 8 : 0) + (zip64DiskNumberStart ? 4 : 0);
6069
+ const extraFieldZip64 = createRecordWriter(length);
6070
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
6071
+ extraFieldZip64.uint16(length - 4);
6072
+ if (zip64UncompressedSize) {
6073
+ extraFieldZip64.uint64(uncompressedSize);
6074
+ }
6075
+ if (zip64CompressedSize) {
6076
+ extraFieldZip64.uint64(compressedSize);
6077
+ }
6078
+ if (zip64Offset) {
6079
+ extraFieldZip64.uint64(fileEntry.offset);
6080
+ }
6081
+ if (zip64DiskNumberStart) {
6082
+ extraFieldZip64.uint32(fileEntry.diskNumberStart);
6083
+ }
6084
+ rawExtraFieldZip64 = extraFieldZip64.array;
5617
6085
  } else {
5618
6086
  rawExtraFieldZip64 = new Uint8Array();
5619
6087
  }
@@ -5621,32 +6089,41 @@ async function closeFile(zipWriter, comment, options) {
5621
6089
  fileEntry.zip64Offset = zip64Offset;
5622
6090
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
5623
6091
  let rawExtraFieldTimestamp;
5624
- if (extendedTimestamp) {
5625
- rawExtraFieldTimestamp = new Uint8Array(9);
5626
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldTimestamp);
5627
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5628
- setUint16(extraFieldExtendedTimestampView, 2, 5);
5629
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5630
- setUint32(extraFieldExtendedTimestampView, 5, Math.floor(lastModDate.getTime() / 1000));
6092
+ const lastModTimeUnix = getTimeUnix(lastModDate);
6093
+ if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
6094
+ const extraFieldTimestamp = createRecordWriter(9);
6095
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
6096
+ extraFieldTimestamp.uint16(5);
6097
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
6098
+ extraFieldTimestamp.uint32(lastModTimeUnix);
6099
+ rawExtraFieldTimestamp = extraFieldTimestamp.array;
5631
6100
  } else {
5632
6101
  rawExtraFieldTimestamp = new Uint8Array();
5633
6102
  }
5634
6103
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
5635
- directoryDataLength += 46 +
5636
- getLength(
5637
- rawFilename,
5638
- rawComment,
5639
- rawExtraFieldZip64,
5640
- rawExtraFieldAES,
5641
- rawExtraFieldNTFS,
5642
- rawExtraFieldUnix,
5643
- rawExtraFieldTimestamp,
5644
- rawExtraField);
6104
+ const extraFieldLength = getLength(
6105
+ rawExtraFieldZip64,
6106
+ rawExtraFieldAES,
6107
+ rawExtraFieldNTFS,
6108
+ rawExtraFieldUnix,
6109
+ rawExtraFieldTimestamp,
6110
+ rawExtraField);
6111
+ if (extraFieldLength > MAX_16_BITS) {
6112
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
6113
+ }
6114
+ directoryDataLength += CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
5645
6115
  }
6116
+ return directoryDataLength;
6117
+ }
6118
+
6119
+ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
6120
+ const { files, writer } = zipWriter;
5646
6121
  const directoryArray = new Uint8Array(directoryDataLength);
5647
- const directoryView = getDataView(directoryArray);
5648
6122
  await initStream(writer);
6123
+ let offset = 0;
5649
6124
  let directoryDiskOffset = 0;
6125
+ let cdStartDiskNumber = writer.diskNumber;
6126
+ let cdStartDiskOffset = writer.diskOffset;
5650
6127
  for (const [indexFileEntry, fileEntry] of Array.from(files.values()).entries()) {
5651
6128
  const {
5652
6129
  offset: fileEntryOffset,
@@ -5672,52 +6149,46 @@ async function closeFile(zipWriter, comment, options) {
5672
6149
  compressedSize
5673
6150
  } = fileEntry;
5674
6151
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5675
- setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE);
5676
- setUint16(directoryView, offset + 4, versionMadeBy);
6152
+ const directoryRecordLength = CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
6153
+ if (offset + directoryRecordLength - directoryDiskOffset > writer.availableSize) {
6154
+ await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
6155
+ directoryDiskOffset = offset;
6156
+ writer.availableSize = 0;
6157
+ await writeData(writer, new Uint8Array());
6158
+ }
6159
+ if (indexFileEntry == 0) {
6160
+ cdStartDiskNumber = writer.diskNumber;
6161
+ cdStartDiskOffset = writer.diskOffset;
6162
+ }
5677
6163
  if (!zip64UncompressedSize) {
5678
6164
  setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, uncompressedSize);
5679
6165
  }
5680
6166
  if (!zip64CompressedSize) {
5681
6167
  setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, compressedSize);
5682
6168
  }
5683
- arraySet(directoryArray, headerArray, offset + 6);
5684
- let directoryOffset = offset + HEADER_SIZE;
5685
- setUint16(directoryView, directoryOffset, extraFieldLength);
5686
- directoryOffset += 2;
5687
- setUint16(directoryView, directoryOffset, getLength(rawComment));
5688
- directoryOffset += 2;
5689
- setUint16(directoryView, directoryOffset, zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
5690
- directoryOffset += 2;
5691
- setUint16(directoryView, directoryOffset, internalFileAttributes);
5692
- directoryOffset += 2;
5693
- if (externalFileAttributes) {
5694
- setUint32(directoryView, directoryOffset, externalFileAttributes);
5695
- }
5696
- directoryOffset += 4;
5697
- setUint32(directoryView, directoryOffset, zip64Offset ? MAX_32_BITS : fileEntryOffset);
5698
- directoryOffset += 4;
5699
- arraySet(directoryArray, rawFilename, directoryOffset);
5700
- directoryOffset += getLength(rawFilename);
5701
- arraySet(directoryArray, rawExtraFieldZip64, directoryOffset);
5702
- directoryOffset += getLength(rawExtraFieldZip64);
5703
- arraySet(directoryArray, rawExtraFieldAES, directoryOffset);
5704
- directoryOffset += getLength(rawExtraFieldAES);
5705
- arraySet(directoryArray, rawExtraFieldExtendedTimestamp, directoryOffset);
5706
- directoryOffset += getLength(rawExtraFieldExtendedTimestamp);
5707
- arraySet(directoryArray, rawExtraFieldNTFS, directoryOffset);
5708
- directoryOffset += getLength(rawExtraFieldNTFS);
5709
- arraySet(directoryArray, rawExtraFieldUnix, directoryOffset);
5710
- directoryOffset += getLength(rawExtraFieldUnix);
5711
- arraySet(directoryArray, rawExtraField, directoryOffset);
5712
- directoryOffset += getLength(rawExtraField);
5713
- arraySet(directoryArray, rawComment, directoryOffset);
5714
- directoryOffset += getLength(rawComment);
5715
- if (offset - directoryDiskOffset > writer.availableSize) {
5716
- writer.availableSize = 0;
5717
- await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
5718
- directoryDiskOffset = offset;
5719
- }
5720
- offset = directoryOffset;
6169
+ if ((zip64Offset || zip64DiskNumberStart) && fileEntry.version < VERSION_ZIP64) {
6170
+ setUint16(headerView, HEADER_OFFSET_VERSION, VERSION_ZIP64);
6171
+ }
6172
+ const directoryRecord = createRecordWriter(directoryRecordLength);
6173
+ directoryRecord.uint32(CENTRAL_FILE_HEADER_SIGNATURE);
6174
+ directoryRecord.uint16(versionMadeBy);
6175
+ directoryRecord.bytes(headerArray.subarray(0, HEADER_SIZE - 4 - 2));
6176
+ directoryRecord.uint16(extraFieldLength);
6177
+ directoryRecord.uint16(getLength(rawComment));
6178
+ directoryRecord.uint16(zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
6179
+ directoryRecord.uint16(internalFileAttributes);
6180
+ directoryRecord.uint32(externalFileAttributes);
6181
+ directoryRecord.uint32(zip64Offset ? MAX_32_BITS : fileEntryOffset);
6182
+ directoryRecord.bytes(rawFilename);
6183
+ directoryRecord.bytes(rawExtraFieldZip64);
6184
+ directoryRecord.bytes(rawExtraFieldAES);
6185
+ directoryRecord.bytes(rawExtraFieldExtendedTimestamp);
6186
+ directoryRecord.bytes(rawExtraFieldNTFS);
6187
+ directoryRecord.bytes(rawExtraFieldUnix);
6188
+ directoryRecord.bytes(rawExtraField);
6189
+ directoryRecord.bytes(rawComment);
6190
+ arraySet(directoryArray, directoryRecord.array, offset);
6191
+ offset += directoryRecordLength;
5721
6192
  if (options.onprogress) {
5722
6193
  try {
5723
6194
  await options.onprogress(indexFileEntry + 1, files.size, new Entry(fileEntry));
@@ -5727,36 +6198,53 @@ async function closeFile(zipWriter, comment, options) {
5727
6198
  }
5728
6199
  }
5729
6200
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
6201
+ return { cdStartDiskNumber, cdStartDiskOffset };
6202
+ }
6203
+
6204
+ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
6205
+ const { writer } = zipWriter;
6206
+ const { cdStartDiskNumber, cdStartDiskOffset } = cdInfo;
6207
+ let { directoryDataLength } = cdInfo;
6208
+ let filesLength = zipWriter.files.size;
6209
+ let diskNumber = cdStartDiskNumber;
6210
+ let directoryOffset = zipWriter.offset - cdStartDiskOffset - (cdStartDiskNumber ? zipWriter.initialOffset : 0);
5730
6211
  let lastDiskNumber = writer.diskNumber;
5731
- const { availableSize } = writer;
5732
- if (availableSize < END_OF_CENTRAL_DIR_LENGTH) {
6212
+ if (writer.availableSize < END_OF_CENTRAL_DIR_LENGTH) {
5733
6213
  lastDiskNumber++;
5734
6214
  }
5735
6215
  let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5736
- if (directoryOffset > MAX_32_BITS || directoryDataLength > MAX_32_BITS || filesLength > MAX_16_BITS || lastDiskNumber > MAX_16_BITS) {
6216
+ if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || filesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
5737
6217
  if (zip64 === false) {
5738
6218
  throw new Error(ERR_UNSUPPORTED_FORMAT);
5739
6219
  } else {
5740
6220
  zip64 = true;
5741
6221
  }
5742
6222
  }
5743
- const endOfdirectoryArray = new Uint8Array(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
5744
- const endOfdirectoryView = getDataView(endOfdirectoryArray);
5745
- offset = 0;
6223
+ const commentLength = getLength(comment);
6224
+ if (commentLength > MAX_16_BITS) {
6225
+ throw new Error(ERR_INVALID_COMMENT);
6226
+ }
6227
+ const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6228
+ if (getLength(endOfdirectoryRecord.array) + commentLength > writer.availableSize) {
6229
+ writer.availableSize = 0;
6230
+ await writeData(writer, new Uint8Array());
6231
+ }
6232
+ lastDiskNumber = writer.diskNumber;
5746
6233
  if (zip64) {
5747
- setUint32(endOfdirectoryView, 0, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
5748
- setBigUint64(endOfdirectoryView, 4, BigInt(44));
5749
- setUint16(endOfdirectoryView, 12, 45);
5750
- setUint16(endOfdirectoryView, 14, 45);
5751
- setUint32(endOfdirectoryView, 16, lastDiskNumber);
5752
- setUint32(endOfdirectoryView, 20, diskNumber);
5753
- setBigUint64(endOfdirectoryView, 24, BigInt(filesLength));
5754
- setBigUint64(endOfdirectoryView, 32, BigInt(filesLength));
5755
- setBigUint64(endOfdirectoryView, 40, BigInt(directoryDataLength));
5756
- setBigUint64(endOfdirectoryView, 48, BigInt(directoryOffset));
5757
- setUint32(endOfdirectoryView, 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
5758
- setBigUint64(endOfdirectoryView, 64, BigInt(directoryOffset) + BigInt(directoryDataLength));
5759
- setUint32(endOfdirectoryView, 72, lastDiskNumber + 1);
6234
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
6235
+ endOfdirectoryRecord.uint64(44);
6236
+ endOfdirectoryRecord.uint16(45);
6237
+ endOfdirectoryRecord.uint16(45);
6238
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6239
+ endOfdirectoryRecord.uint32(diskNumber);
6240
+ endOfdirectoryRecord.uint64(filesLength);
6241
+ endOfdirectoryRecord.uint64(filesLength);
6242
+ endOfdirectoryRecord.uint64(directoryDataLength);
6243
+ endOfdirectoryRecord.uint64(directoryOffset);
6244
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
6245
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6246
+ endOfdirectoryRecord.uint64(BigInt(zipWriter.offset) + BigInt(directoryDataLength) - BigInt(writer.diskOffset) - BigInt(writer.diskNumber ? zipWriter.initialOffset : 0));
6247
+ endOfdirectoryRecord.uint32(lastDiskNumber + 1);
5760
6248
  const supportZip64SplitFile = getOptionValue(zipWriter, options, OPTION_SUPPORT_ZIP64_SPLIT_FILE, true);
5761
6249
  if (supportZip64SplitFile) {
5762
6250
  lastDiskNumber = MAX_16_BITS;
@@ -5765,29 +6253,40 @@ async function closeFile(zipWriter, comment, options) {
5765
6253
  filesLength = MAX_16_BITS;
5766
6254
  directoryOffset = MAX_32_BITS;
5767
6255
  directoryDataLength = MAX_32_BITS;
5768
- offset += ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
5769
- }
5770
- setUint32(endOfdirectoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE);
5771
- setUint16(endOfdirectoryView, offset + 4, lastDiskNumber);
5772
- setUint16(endOfdirectoryView, offset + 6, diskNumber);
5773
- setUint16(endOfdirectoryView, offset + 8, filesLength);
5774
- setUint16(endOfdirectoryView, offset + 10, filesLength);
5775
- setUint32(endOfdirectoryView, offset + 12, directoryDataLength);
5776
- setUint32(endOfdirectoryView, offset + 16, directoryOffset);
5777
- const commentLength = getLength(comment);
5778
- if (commentLength) {
5779
- if (commentLength <= MAX_16_BITS) {
5780
- setUint16(endOfdirectoryView, offset + 20, commentLength);
5781
- } else {
5782
- throw new Error(ERR_INVALID_COMMENT);
5783
- }
5784
6256
  }
5785
- await writeData(writer, endOfdirectoryArray);
6257
+ endOfdirectoryRecord.uint32(END_OF_CENTRAL_DIR_SIGNATURE);
6258
+ endOfdirectoryRecord.uint16(lastDiskNumber);
6259
+ endOfdirectoryRecord.uint16(diskNumber);
6260
+ endOfdirectoryRecord.uint16(filesLength);
6261
+ endOfdirectoryRecord.uint16(filesLength);
6262
+ endOfdirectoryRecord.uint32(directoryDataLength);
6263
+ endOfdirectoryRecord.uint32(directoryOffset);
6264
+ endOfdirectoryRecord.uint16(commentLength);
6265
+ await writeData(writer, endOfdirectoryRecord.array);
5786
6266
  if (commentLength) {
5787
6267
  await writeData(writer, comment);
5788
6268
  }
5789
6269
  }
5790
6270
 
6271
+ function createRecordWriter(length) {
6272
+ const array = new Uint8Array(length);
6273
+ const view = getDataView(array);
6274
+ let offset = 0;
6275
+ return {
6276
+ array,
6277
+ uint8: value => { setUint8(view, offset, value); offset += 1; },
6278
+ uint16: value => { setUint16(view, offset, value); offset += 2; },
6279
+ uint32: value => { setUint32(view, offset, value); offset += 4; },
6280
+ uint64: value => { setBigUint64(view, offset, BigInt(value)); offset += 8; },
6281
+ bytes: value => { arraySet(array, value, offset); offset += getLength(value); },
6282
+ skip: count => offset += count
6283
+ };
6284
+ }
6285
+
6286
+ function getSegmentOffset(zipWriter, writer) {
6287
+ return zipWriter.offset - writer.diskOffset - (writer.diskNumber ? zipWriter.initialOffset : 0);
6288
+ }
6289
+
5791
6290
  async function writeData(writer, array) {
5792
6291
  const { writable } = writer;
5793
6292
  const streamWriter = writable.getWriter();
@@ -5800,12 +6299,40 @@ async function writeData(writer, array) {
5800
6299
  }
5801
6300
  }
5802
6301
 
6302
+ async function flushBufferedData(readable, writer, signal, onChunkWritten) {
6303
+ const streamWriter = writer.writable.getWriter();
6304
+ try {
6305
+ await readable.pipeTo(new WritableStream({
6306
+ async write(chunk) {
6307
+ await streamWriter.ready;
6308
+ await streamWriter.write(chunk);
6309
+ onChunkWritten(getLength(chunk));
6310
+ }
6311
+ }), { preventClose: true, preventAbort: true, signal });
6312
+ } finally {
6313
+ streamWriter.releaseLock();
6314
+ }
6315
+ }
6316
+
5803
6317
  function getTimeNTFS(date) {
5804
6318
  if (date) {
5805
6319
  return ((BigInt(date.getTime()) + BigInt(11644473600000)) * BigInt(10000));
5806
6320
  }
5807
6321
  }
5808
6322
 
6323
+ function getTimeUnix(date) {
6324
+ return Math.floor(date.getTime() / 1000);
6325
+ }
6326
+
6327
+ // the extended timestamp extra field stores dates as signed 32-bit time_t values
6328
+ function inUnixTimeRange(timeUnix) {
6329
+ return timeUnix >= MIN_UNIX_TIME && timeUnix <= MAX_UNIX_TIME;
6330
+ }
6331
+
6332
+ function clampUnixTime(timeUnix) {
6333
+ return Math.min(MAX_UNIX_TIME, Math.max(MIN_UNIX_TIME, timeUnix));
6334
+ }
6335
+
5809
6336
  function getOptionValue(zipWriter, options, name, defaultValue) {
5810
6337
  const result = options[name] === UNDEFINED_VALUE ? zipWriter.options[name] : options[name];
5811
6338
  return result === UNDEFINED_VALUE ? defaultValue : result;
@@ -5836,7 +6363,7 @@ function arraySet(array, typedArray, offset) {
5836
6363
  }
5837
6364
 
5838
6365
  function getDataView(array) {
5839
- return new DataView(array.buffer);
6366
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
5840
6367
  }
5841
6368
 
5842
6369
  function getLength(...arrayLikes) {
@@ -5852,30 +6379,39 @@ function getHeaderArrayData({
5852
6379
  uncompressedSize,
5853
6380
  compressedSize,
5854
6381
  lastModDate,
6382
+ rawLastModDate,
5855
6383
  rawFilename,
5856
6384
  zip64CompressedSize,
5857
6385
  zip64UncompressedSize,
5858
6386
  extraFieldLength
5859
6387
  }) {
5860
- const headerArray = new Uint8Array(HEADER_SIZE - 4);
6388
+ const headerRecord = createRecordWriter(HEADER_SIZE - 4);
6389
+ const headerArray = headerRecord.array;
5861
6390
  const headerView = getDataView(headerArray);
5862
- setUint16(headerView, 0, version);
5863
- setUint16(headerView, 2, bitFlag);
5864
- setUint16(headerView, 4, compressionMethod);
5865
- const dateArray = new Uint32Array(1);
5866
- const dateView = getDataView(dateArray);
5867
- setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
5868
- setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
5869
- const rawLastModDate = dateArray[0];
5870
- setUint32(headerView, 6, rawLastModDate);
6391
+ headerRecord.uint16(version);
6392
+ headerRecord.uint16(bitFlag);
6393
+ headerRecord.uint16(compressionMethod);
6394
+ if (rawLastModDate === UNDEFINED_VALUE) {
6395
+ const dateArray = new Uint32Array(1);
6396
+ const dateView = getDataView(dateArray);
6397
+ setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
6398
+ setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
6399
+ rawLastModDate = dateArray[0];
6400
+ }
6401
+ headerRecord.uint32(rawLastModDate);
6402
+ headerRecord.skip(4);
5871
6403
  if (zip64CompressedSize || compressedSize !== UNDEFINED_VALUE) {
5872
- setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, zip64CompressedSize ? MAX_32_BITS : compressedSize);
6404
+ headerRecord.uint32(zip64CompressedSize ? MAX_32_BITS : compressedSize);
6405
+ } else {
6406
+ headerRecord.skip(4);
5873
6407
  }
5874
6408
  if (zip64UncompressedSize || uncompressedSize !== UNDEFINED_VALUE) {
5875
- setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6409
+ headerRecord.uint32(zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6410
+ } else {
6411
+ headerRecord.skip(4);
5876
6412
  }
5877
- setUint16(headerView, 22, getLength(rawFilename));
5878
- setUint16(headerView, 24, extraFieldLength);
6413
+ headerRecord.uint16(getLength(rawFilename));
6414
+ headerRecord.uint16(extraFieldLength);
5879
6415
  return {
5880
6416
  headerArray,
5881
6417
  headerView,
@@ -5976,7 +6512,7 @@ try {
5976
6512
  // ignored
5977
6513
  }
5978
6514
 
5979
- const A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function g(g){let B;g({wasmURI:()=>(B||(B="data:application/wasm;base64,"+(g=>{g=(g=>{const B=(g=(g+"").replace(/[^A-Za-z0-9+/=]/g,"")).length,E=[];for(let I=0;B>I;I+=4){const B=A.indexOf(g[I])<<18|A.indexOf(g[I+1])<<12|(63&A.indexOf(g[I+2]))<<6|63&A.indexOf(g[I+3]);E.push(B>>16&255),"="!==g[I+2]&&E.push(B>>8&255),"="!==g[I+3]&&E.push(255&B);}return new Uint8Array(E)})(g);let B=new Uint8Array(1024),E=0;for(let A=0;A<g.length;){const C=g[A++];if(128&C){const Q=3+(127&C),D=g[A++]<<8|g[A++],o=E-D;I(E+Q);for(let A=0;Q>A;A++)B[E++]=B[o+A];}else {const Q=C;I(E+Q);for(let I=0;Q>I&&A<g.length;I++)B[E++]=g[A++];}}return (g=>{let B="";const E=g.length;let I=0;for(;E>I+2;I+=3){const E=g[I]<<16|g[I+1]<<8|g[I+2];B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+A[63&E];}const C=E-I;if(1===C){const E=g[I]<<16;B+=A[E>>18&63]+A[E>>12&63]+"==";}else if(2===C){const E=g[I]<<16|g[I+1]<<8;B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+"=";}return B})(new Uint8Array(B.buffer.slice(0,E)));function I(A){if(B.length<A){let g=2*B.length;for(;A>g;)g*=2;const I=new Uint8Array(g);I.set(B.subarray(0,E)),B=I;}}})("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BAGZgAAEAVmAAAQB2YAABAE5gAAEAbmAAAQBeYAABAH5gAAEAQWAAAQBhYAABAFFgAAEAcWAAAQBJYAABAGlgAAEAWWAAAQB5YAABAEVgAAEAZWAAAQBVYAABAHVgAAEATWAAAQBtYAABAF1gAAEAfWAAAQBDYAABAGNgAAEAU2AAAQBzYAABIARMwIArYAABAFtgAAEAe2AAAQBHYAABAGdgAAEAV2AAAQB3YAABAE9gAAEAb2AAAQBfYAABAH9gAAEAROAAMIFEwEJAJOAAAgBk4AACAFTgAAIAVOAAAgB04AACAHTgAAIATOAAAgBM4AACAGzgAAIAbOAAAgBc4AACAFzgAAIAfOAAAgB84AACAELgAAIgBDagAQCgAAEgAAIAUuAAAgBS4AACAHLgAAIAcuAAAgBK4AACAErgAAIAauAAAgBq4AACAFrgAAIAWuAAAgB64AACAHrgAAIARuAAAgBG4AACAGbgAAIAZuAAAgBW4AACAFbgAAIAduAAAgB24AACAE7gAAIATuAAAgBu4AACAG7gAAIAXuAAAgBe4AACAH7gAAIAfuAAAiBA7YBB4AACAGHgAAIAYeAAAgBR4AACAFHgAAIAceAAAgBx4AACAEngAAIASeAAAgBp4AACAGngAAIAWeAAAgBZ4AACAHngAAIAeeAAAgBF4AACAEXgAAIAZeAAAgBl4AACAFXgAAIAVeAAAgB14AACAHXgAAIATeAAAgBN4AACAG3gAAIAbeAAAgBd4AACAF3gAAIAfeAAAgB94AACAEPgAAIAQ+AAAgBj4AACAGPgAAIAU+AAAgBT4AACAHPgAAIAc+AAAgBL4AACAEvgAAIAa+AAAgBr4AACAFvgAAIAW+AAAgB74AACAHvgAAIAR+AAAgBH4AACAGfgAAIAZ+AAAgBX4AACAFfgAAIAd+AAAgB34AACAE/gAAIAT+AAAgBv4AACAG/gAAIAX+AAAgBf4AACAH/gAAIAf+AAAiBBAoBQIAABAEggAAEAWCAAAQBEIAABAFQgAAEATCAAAQBcIIFVgMHAEiAAAQBKIAABAFogAAEARiAAAQBWIAABAE4gAAEAXiAAAQBBIAABAFEgAAEASSAAAQBZIAABAEUgAAEAVSAAAQBNIAABAF0gAAEAQOAAEIBg4AABAFDgAAEAcOAAAQBI4AABAGjgAAEAWOAAAQB44AABIC+K4AAdIECxgEFgABcAQWCBUoBFIAABAEMgAAEARyAAASAvlaABEQBBYIGBAEaggXqAQWAA9QBBYADuAEFgAOcgE92gAAEARGAAAQBCYAABAEZgAAEgQACARWAAAQBDYAABAEdgAAEgL59gAKkgQZAAQWAAiyBBaYBBYABtAEFgD3fAxsLTYMfuYcABIC+rooABIEHUYkABAEEjAAEAQWKAAQEQbAcC4C9CosAS40AO4UALwEGhAAEgQWIgQAEgQEKgQAEgQGSgQAEgIS2ggAEAQuEAAQBDIQABIAF24FHeQTgHQsjhQBfhQXLAhARgAVtBgcJBgoFC4A6uAQNAg4BgAclBJQeC2mFAJCFAIiFAICFAHiBAGiBAFyBBh8BEIAABAEUgAAEARiAAAQBHIAABAEggAAEASiAAAQBMIAABAE4gAAEAUCAAAQBUIAABIEGvQFwgAAEAYCAAAQBoIAABAHAgAAEAeCAAG8DHwtyjQBvgQBrgQBngQBjgQBfgQBbgQBXgQBTgQBPgQBLgQBHgQBDgQE8AYCvAEGAUc0CC22BAMcBBIAAAgEIgAAEgQEzgQJLARCAAA6DAAyBnqyAqmuEACSBB3OBAE8BCIAACIEAGIUADIEIt4MADAEggQCUgDKEgQBrAYCBCC8BBIMADIA/SAoBABAMAEGRIQv/gCUfgMDAgIKxBQgJCQoKgEk3gAABAQ2AAAEBDoAAAQEPgAABARCEAAEBEYQAAQEShAABAROEAAEBFIwAAQEVjAABARaMAAEBF4wAAQEYnAABARmcAAEBGpwAAQEbmwABARyBffsEBAQFBYHB1QEHgAABAQiEAAGAXSqCAAEBCowAAYAnsooAAYEBMJkAAYEBTJkAAYEBaLkAAYEBpLkAAYIDdYABzoUBvI0BqJ0BkLwBgAIbHLwAAQEdvAABgA9PgH05A9AqAQ==")),B)});}
6515
+ 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;}}})("FABhc20BAAAAAUULYAF/AX9gA39/gQAHBAJ/fwCBAAWAAAsBAYAACgEGgAAWgwAZgQAgAwBgAIAAA4AADQEEgQAVAwBgB4MAHoAAHxIDQ0IHAAQCAAQICAADAAUDCgCAAAeBAAMBBYEABwMBAwOBAAgQAgEABQYAAQEFBAkEBAkCBoAAAR4AAwQBAwQDAwIEBwEBBAUBcAENDQUGAQGCAoICBgiAAJkiQdDVBAsHigQcBm1lbW9yeQIADGluZmxhdGU5X25ldwAHDYYADwdpbml0AAgRigAQB19yYXcAChCGABQJcHJvY2VzcwALhwBGBmVuZAAOFoYADxBsYXN0X2NvbnN1bWVkABELhAAZgwBthQA2gwBsARKFAFiHAGsBFIUAf4MAEwdnemlwABUPhQAUhQB+ARaGAFaBAH0CGBWFAA6NAHwCZGWJAHyFAA6CAHwCGhCJAA+CAHwCHBGKABOCAHwCHQ+FABSFAHwBHoYAVoEAfAkgBGZyZWUAAhWFABWMAIMKBm1hbGxvYwABC4IAVQppYWxpemUAABlfgAAPFmRpcmVjdF9mdW5jdGlvbl90YWJsZQGAABwbZW1zY3JpcHRlbl9zdGFja19yZXN0b3JlAAUcjgAbAmdlgABvDnVycmVudAAGIl9fY3hhgABbBGNyZW2AABIGX2V4Y2VwggBdBnJlZmNvdYAAJR4+CRIBAEEBCwwAIiMMDxcZHz82OTwMAQsK9eYCQgOAAKkQwycBC38jAEEQayIKJAACQI8AAhIgAEH0AU0EQEGkJygCACIEQRCAABIGC2pB+ANxgQAJEEkbIgZBA3YiAHYiAUEDcQSBADIGAUF/c0EBgAAfBmoiAkEDdIAAGQzMJ2oiACABKALUJyKAAAYECCIFRoIAUgkgBEF+IAJ3cTaAAqoRAQsgBSAANgIMIAAgBTYCCAuAAEgDCGohgAA3ASCCAEaAAAUEcjYCBIEADwNqIgGBAE0DBEEBgQASBwwLCyAGQayCAJ8DCE0NgAAbgQCGBEECIACBADUFACACa3KAADUEAHRxaIEAowN0IgCCAI+AAB+CAI+AAAaLAI8FAXdxIgSGAJEBAoEAkQEChACRAQCAAGiDAIWAAAoDaiIHgACigQDfBSAGayIFgwCMgAAZAgFqgQAuCgAgCARAIAhBeHGBAG4EIQFBuIEAoAQhAgJ/gABlAQGAABkHA3Z0IgNxRYMAeAMDIASAAD6AADyBAHWBASEDCyEDgQDpgAB2gAAchACEAQGDAAcBA4MAi4IBHIAAVgIgB4AAOYAA/oIAdYABCwJBqIIBCQILRYABCQULaEECdIAA5gMpIgKBAS4CeHGAAKqAAFkEAiEBA4IBqAUoAhAiAIAAg4EACgEUgAAKAQ2AAH6AARCEACqAANmBAIUFA0kiARuAADaAAUkBIIAACYABOAEhgQCnAgsggABUAxghCYAAFoAACQQMIgBHgABIgAAKAQiAADeEAcaAALEDCAwKggApBRQiAQR/gAHIAhRqgAFTgQB3AwFFDYAAiQtBEGoLIQUDQCAFIYABTYABmgMUaiGAAgWCADACDQCAAOUBEIQAEIAAMQYNAAsgB0GAAFsIAAwJC0F/IQaAAB8Dv39LggAnAQuAAhKAALUCIQaEAP4IB0UNAEEfIQiAAf6CAPKAAsQD//8HgALGgAHBASaBAlgGdmciAGt2ggKlCkEBdGtBPmohCAuEAvEBCIUBNQEBgQGeAgAhgQIKgQAHgAA8ARmAAB0DAXZrgABXCAhBH0cbdCEChQFJhQE0BAQgA0+AAJMBAYAAtwMEIgOAAIYBAIEByoAARAEDgQI/ggFoAgQgggLFB0EddkEEcWqCANwCRhuAAB0CBBuAAGQBAoAAj4ABZIEA7oEAMQIFcoMAhAEFgALPAQiBAruAAO6AAs8CB3GBAa6AANiFAeEBIYABHYIBwIABTIgBwoACLgJJIYAAbIEByYMBxAEFgQAJhQFTgAGTAQGDAW8DCyIAggByAQWAATkCIAODA02AAEGBAMsBBYEB5wEIgAA5gAAJhAHngAAKjQHngAKTgAAWgwHnAQWCAeeAAA+EAecBBYIB54ABK4ACeoAA+4MB54IDgIgB54IAEIQB5wEEgwHnAQeHA9gBBYEEgoMDQ4AEpoAAjYECnwNBEE+AAI2CA4uAATKGA4ECBWqBAJOAAFeFA66BA1WAABeGA7sBBYsEQIABX4AEJwEhgAHlgANGgQA6gQNWgAN0gQCZgQNlgAJvgABKAbCCAIgCAkmAAIgBsIAAH4IAgYEALAK8J4AAA4EAG4MAiIEAN4kAjYYEMYUAS4QCSgkvaiIDAn9B/CqAADuAAFMChCuAAAiBAmgFiCtCfzeAAFcGgCtCgKCAgAABAQSBAA4R/CogCkEMakFwcUHYqtWqBXOBAHoCkCuCAScDQeAqgwAIBoAgCyIBaoAFooABkwJrIoACI4AEmQVNDQhB3IEAZAIiBYAAZgHUggAKAQiABKMFIgkgCE2AAUcFCUlyDQmAAvmAAEUDLQAAgAKQgAJvhQX6hADYgQA5BOQqIQCDAlqBAD+BAY2AADwBCIICagNqSQ2BAtuBAhKCAkMEQQAQBIAFdwJ/RoAB+QMBIQSAAMmCAR0BQYAAk4AD+4AGIYEC/AFrgQVTAWqCAs0EcWohBIAB8oEAqwEDhACrgQERgwCrgANFgQVnAgVNgAFKAQeAAKuBACqAAF+AAWMFRw0BDAWBADiAAEyAAOuBABaCAkKAAFOBAJUBRoAE/gECggMVgQCKgAEJBUEwaiAEgQC4gAHtAwwEC4MBcYEDIAMgBGuBAIkHAmtxIgIQBIMALgECgAB3gAKqgQArgADcgADNBEcNAguBAWgB4IEAlgFBggWsgAWohADpggDygQBoAXKBBSQDTXINgANTgABQgAPoCAZBKGpNDQULgADOgwDRgQDPggGsAdiCAA4BAIECTgLYKoEDSQEAgQGFgwFxAQOHAXGDANOBA2uAANUCIgWAANeCABKDAWuBAMcBtIMCe4EBSoAAewEbgQQtAbSDAr2CAmkEQegqIIEGzIAAUIIAFQVBxCdBf4EACALIJ4MCe4EADAHwgwJAgQHggwbPgwewgAZQAdSAAxCBBlgC2CeBBSeAALsDQSBHgAB5gQMBBARBKGuAABABeIAA6QFBgQJrgAHegwMOhAegggbOgAN0hQMIBAJqQSiBA2wEwCdBjIEBe4ED4IABzoABgQFNgQZkAktygwDaBAxBCHGBAAqAAdkCBWqBADCAAFEBA4AAZgEDggBmgAhRggN0ArAngwOPgQFPgAAtgACJgwBvgAClggBvgABWkABvAQOCARMCDAaDAAeFAT0DIAJLiAE1gwH7AQWCAYACAkCBBpmEAYKBBPeEAXoDAQwCgQWcAi0AgQCtgATgAQuEAa6BCSyDAa4BA4ECaYEHPIICjAMiBUmEB1kBCIIGTJQBQIIHyIwBQAEHmQFAgABiAgVBgAf4gQBBA2pBL4AAT4AAKAEDgAVMgAmUAwFBG4IJLAlB7CopAgA3AhCAAAsB5IMACwEIgAAUgglbgQBwjQIghAIMgAAgARiABK+CAhOAAJiEBL+AAWsBQYABHoEE4YAA04EDAgMgA0aBBu2DBU0BfoAJx4AG/4EAFoAGeoQAuoIIxQEAgAj2AwJB/4EKR4AACIQJE4AAFYQKVIAFLoEJ44AJEQEChQkRgAARggkRggmGgQE6AQuABseAAN6BCRGAAGCABnkCQQyABbYBCIEFMwEfggc3Af+EB+EBAoAH4YAAGZAH4YAAsYAHAgY2AhwgA0KCARMBAIAHPQNB1CmACZ6CBO+DCDuAArOBCjmCBQqAABOBAomDCZuBAHaCAI8BAoAIB4AAVYIIB4AIZoEIB4IH2oAHpoECMYEK4YIHgAECggOugAfngQdwgQfXgwMSgAf0AiIEgQbrAQWCBuuBAFcBEIEAmoAB8wMYQQiAAWUCAyKACDACQQyFCguAAdeBAPCDAIGBCg+AAMOACNmAACMBGIABAgEMgAA7hAbwgQL2gwRLhAatgAZoAU2ACIKAAm6BB8yxBq+AAyUEoCdBMIEAOYEDNIIIxIMHGoIC24ADLIIDb4UCxwFqgAYdhQBCgAmQgAaHggAVgAUJAiAIgAbwA2shB4UE5QIgBIELcoED3YoD0AEHgwUfgQDlhAvcgAHgggf3gwAxgAeZggAxAqwnhAijjgAxgQIlgwEGgQFAgAFogQWbBANxQQGAAD+AACSACiQBCYEAFoACPYIM24MClIAAEYEI0AECgwwGgwKWgAwKgAA5AXaDDJwBAoEC7IcLh4ECd4EANQMYIQaAAEaABDOBBB6CAEWCAR+BACaBAaWAACaAAB+AABiAC1yACRcBBIIJF4IB+4EJq4AAEIEJF4ALi4IKLoAGjYEJF4IENIAAMIADV4ELHoEJvYIAMYECLAEFgwkXggqOgACSAQaACayDAGABHIAA5AECgAW6gQoKggEpgAF+gALYgwGrAwINAYACyIMC3oEA1YUA0oEAOwIgBoAAXYEAMAEGgQAsARCBANeCAAoBFIAC5oIMDoAI6IACl4QAtYEDXoEA2YADOoEAJQEYggEEggw4gQJFgAAZARSGABkEByAJaoAL0wEEgAAHgQLtAQSBA32BAlaFBCSFBNmAAAoBaoIMwoAAEoMBjAEHkwQgAQetBCCDAymBAAeEAbGABCgBAoEAZoQEKAEHgAQoAQeSBCiAAVuCDXSGBCgBAoUEKIIPIYQEKIIEtQN0IgWFBCiAA9uDAJKGBCgBB4AEKIAFB4IEKAEChAwvggYigwH0gQ56ggQoAQeBBCiBDA+BAe2DC/+BBYGBBCiDC0SCAfyGBCiAANYBGIAAB4QA5IEA8oUBBIEGeoMLk4MEKoECL4EAK4gBCAELgAy5ggPaggIAAQiDAkKAAGYBHIAA0IAAzoACbIACQoEPDoAAioECQoIDXYAG84EA4gEHhA8dgQGvgwBAgAoEhAJAgAoMhAJAggAKgAJAhA5OAiAIgQCEgwDIggutgACGgAaNggDGhQwzgQJAggAZARSFABmAAFwDA0EPgwpnAQOBBKmAA4uHC72DBH2GBCGBDA6EAB+AAAqBBG8BA4YCXgIEaoIBj4AAEoMCXoAITJECXgEDogJegAcqgQJegAAHAQyBAs2DAAeHAl6CAGaEAl4BA4ACXgEDlQaGggA8AxwgBJEGhoEDGoIQuYUCWIACtIQGgIEHqYMAcQEYgQCYAQOWBoeDAl+FD/OAB6OEBoeCCSGBACaBBfKBAl8BB4cPWYEAXgEQgQtPgwPYhQDlgQDzggb0gwTdggAWgATwgQEJgg2lgAQbgwTyggDUgQ4FgwJfggT6AQmDAl+AADyEAl+AAe+AAl+BBWeAACiNAl8BC4MCX4YCXQMCIAmEAl0BCYYCXYIACogCXQEJgQCCgxBQjwJdgxB3mQJdgQv/igJdgAl6jQJdgAUChAAfgAAKgAOSiAJdgA5pggJdihHqgQ4+ggGFgAJhhRHogAFehQJbAQSEAc+IAluCEjWCAVKDEeOED1mCAfEBCIEG/4IR24EOnYEAboEIgIEBYwELgA4SAxBqJIAASgYL3gsBCH+BBs+CAOwEQQhrIoEHDwIEa4IM4oAAmIALOAIhBYEBUoACiYIGWIACXYAGgIAEPYIT0oAAL4MLC4AKp4EC5oQE6IAE6oMHegEDgQbegAArAQyAAkEBBIQDSIAAPoECEoANhwECiQcyAQSGBzKADZyAACIBGIER14YAQYAAMIUA4oES2oEMAIAAFgMUIgKABx0BA4IHHYAADwIQIoAGeoAAm4IHHQEEgALKAQSAEeoBAoACQIAHHYABIYIAMIEKdIEHHYIAEIAAMYECwgEGgwcdgAijgAJmgQ2ZgAf1AgNHgA5UgAE4ggJngA5+hgZ/hQgtghRxAgAPgQHmiQCZgA3tgRAQASCBEkeBAi6BAsEBBIcFIAEDhwUggwuoiwdiAQSIAsWABuCEAsWAAQmEAsWCAAqAAsWAApuBCeOBBv+ABaaCAMmDDx6BAsWCAJGAAsWDASGBAdmCABkBFIcAGQIgBYQRngEEgACcAQGAAdKGFb+AAYeDBD+DCWuCFN2OCWuADUyMCToBA4MB8AJHDYERdYMQUwG4gwAIAQ+ECYWBD4uSCYePAE2GCYeAAV2CBIeAAoSCAK6JAkaCEkiAANGMCXiKAkaOAjOEEpCAB3CGEouLACSDAgODAleIEouAAUWADLi0AleACBSACbuOAkCHCm2CDl2BBv+IB1OIAjOIB1OdAjOJB1WFAjOCAAqIAjOHB1WQAjODAP2SAjOOALiBAqGAD9OFAyWAAa2FCxSBCyyCBNGAFrOGF/yBBkKBBNEBAIUEz4AEL4IEzwEChQYlAQuCBl+CCICEDLiEFsCDDLiAAkoBH4IGiIUHKQEAgAcpgASzgAcpAQKDBymBCQKCBymBBuOBALmGCYeBBkOCBykCBAKABO6AAJaDCYkBBoAAlgEBigcxAQaCAJOCDVqBDSWADuyCBW2ABzCAB+yCBzABAYMHMIACioEFq4ICD4YHMAEAgQcwAQGBBzCBDMWABzCCEhCCBzCBCy4CIgSCAheCCY+BAF2BFNQBQYIA9wIDIoYBBoEIhIcXroAAJ4AA44AAiAIAC4ACdYAFEIASi4MBfIIBGoIBjYALZ4IRngHEggISgBAPgBJRAiAAgA/FgBNTBIwLAQeAAA2AE7eBBceDEGeBBOKKBc6CEHuAALmECEiBACaBEoWEBo+EEL8BDIEX/oUJC4MKNAEEjAXDgQ+JhgN9gAAigAzkgQCihhEAggDThAHWggOQggywAQSAA2yBFdeEFloBBIIWnYgV94AHAoAGZoIV94IE0oABRYIF44MAEIQBVYQX3pIFw4IDNocFw4EBw4UFw4EAG4EEZoUAmYIItIIFw4AASoQNJYAAlgEcgABRgAOQgAHygAOQAQCBA2ABBIIDkIMKIIsDkIQak4IDkIAPFYYNJYEB9YMNJYAACoADkAEDggOQgAhFgQOQggD6gQOQggEcgQOQgAAlgAN3ggEhggOQggAZgQOQggAZhgWvhADukQW0ggWGhgW0gBODhBbahg+ynwW0gBWwhAW0ggAfhgW0kABNgRq8hAFOgQg4ggJNgwW0hwI3ggVxgAFsjAW0igI3iwGLhQW0gAE1igW0iQJIhQW0gQJIiAW0gAJIhQW0rwJIggW0jwIxhgDmgwW0hwIkggW0iAIkggW0owIkgAx4owIkhgW0jAIkhwW0iwIkkQC4gQ1VhAW0hAGtAQGFCZaPBbSACq6BHKaABbSACCOFDN6BCtCKBbSBBOOBBZ+FCnyEEMeDCpiCBbSABYuGBbQBAYYbRI0FtIISIYAAuQMcIACDBbQBA4UFtIARb4YPO4EGSIAWaQEHhxNjgwsUggCEghbKhAzjAQGABbOAAMGCBbMBA4MFs4ABH4EFs4ICDoIQWoICqIEFswEDgQWzgQAHgAWzgAJ6gACVhgzjggfKAQeFELuAApWCAVmEAOqDBpeFEgSEDdaCAQ2AEvWCA9iDDPeDAQ0DCwtJgQvaAZCDDjuBFR8BaoELYgECggs1gAB0ggNQgheJAyAAP4AFAgF0gB6RhxNFAX+AAUwBkIQKkAMBCwaAAC0GJAALBAAjgBOzAgEBgAbVBEHEABCAEBmDC8gCBGuBGZOAHiSCAA6ABh4DAPwLgRjSggVrgAEjASSBB40FNgIgIACAEhkDCwsRgAAmgQFRAX6CB8ULEBAJC9kCAQN/QXqABzAEQEGUCIEATQExgQI4AX6BDHKEAFWEBLgBIIMCfIAACgEkhAAICihBAUHYNyACEQGABlaBAFcBfIEAV4MRF4AA5gM2AjiFAa8EAkG//oAACYAAZQQgABAkgxYPBkEfdSIDc4EWCIABj4AUBYAWLoMC0gEogw58AnZBghn+gAcSAU6AHl0BIoMQtoIAPYIAXAM0IAKBAj8BLIkAFIAA54EAB4ABloEAG4ANzYIN8YAAX4ADhgEwgALIgQAWATyDACsBJIAAB4AbOYIOHAFCgRtEAXCCEcYBQoAAqAE3gQ3IAkKBgwAUAcyAAOCAACsCtAqCCr4BcIMA0QFUgwAHAlBBggkNgAEJgxmFAiQRghwQgQ+5gAIsjAFtAXCAAW0BEoIB+oIOU4AGlQlBBBANC4YlASKEIV0CFCSBAXgBGYYBJIEHjAIiEoQBbAMEIROEG1uBAjcBE4AEZwMAIROCAH2BBJAB3IALOgEfgACnBfQFaiEVgAAIAdiAABABG4AACAHwgAAIARqDAL8CIRaBACCAABADEUGcgRgdBCEcQZiCAAgEHUGUK4AB+AIhHoEDNgNAIQqBAAcBPIENlAFBgBg2CAJJISBBfSENgAAOBgZHISEgE4ECGIEDLwMXIRCBGPyRIg6UAAKBCZCRIjyBCVSACaGAAXkXaw4TBAUGBwgJAwIMDQEaABwPIyMVIiOCBIEFTCEGDBqGAAqAFtKAAAoBbIEeUoEACAEigAlGAygCYIAO0wUDIAxJG4AAIQQGCyAggR/ggABWgAZUBQ4hDQwdgwTIAg0QgA8UAghygBXiAQiBBAKCF48DCkECgga2A0UNDoEajgFrgBVqAQOAARIDIAp0gBR6gAEKgAJBgAS3BCAJIQqDINSBEYCAAlIDCEHBgABegALUhgDLgAAYAXaCFkkCaw6AIzkBAoAE6gEegQ12gh+eBQgDQEGQgBztgA/vA5ABRoEBxQERgSApBnRqQQg7AYEgLIAAZIEKhIAfngNBgAKADL2AHRcBAoQAKIAFDYAAKAEJgQAogAALgArdhAAoAZiBHywBCIAAB4oAUAEHjQBQgAA1AaCLAEuCAHOHAEuAAJ8BBIACDgNBoCuBBIECoDyDAAkDIBRBgBE8AQyABYkBEYAAQIAAF4AAEQcMaiAVECUaggBUASCKAFMBBYwAUwGcgABPATyBArEBHIMAS4AQoAEMgCChAxFBIIoASoACfQNBATqABHcDoCshgQGjAiAdgANYgAN/AYmAA38B0IADiwFYgAATgABCgANyAkHHggRDAkEBgAKqASGACjsCCkGAGC0BCoIV9QIhB4EAHYEIPYEghYABFIEB8YASLQHEgQGggwvYAsILgRk7AdGBABGCG8GAAEqBER6IAEOFAD0CDBuBABmAGAUBBYAGDwEKgBidgAAcgRm0AkEfghgHggfwgAIkgAF5gQIkAQWEAiSDAXCDEtsDBQwCgAVugAFTgQIgAQaAAFQBCoIAkQEegAWagQh5BP//A3GAAqsBB4ElAgIQdoILNQJB3YMSpoEAoYIKsYACawQbC0HCggBAAQKBAAiEHLMDNgJEgABagAi9gABUgQOTgAQdgQBbgACzAwJBw4IAJoIC5wFEgR4hggRmgAAEgBvrAgMggAdnAiAQgQAKgQKOgAAqhAMWgAA5ARKADjoCAxCAGxGCADmABZCAAGSAAC0EEmohEoEANgJrIYEAO4AA1oESfIAADgMEDBmBAG2DBdABDIEKooIDQgINS4EYrowBHYUDQYQBHYADeQFqgwNEggEegQGegwCGgQBSgAEQAR+AARcDQYECgBowAWSCABACBXaAABOAADsDNgJoggAQBQp2QQ9xgBxeASKACScBYIAATgEOgwG9AQ6CAb0CQR6CIekCQaGKAUqAAKGAAAwBxYMCOgIAIYAEKIEFnwFsgAMVgAOvAwYgDIEKogETgAAJBwZBE00bIQmAAMsDBiAJghdsgAATgAr+gAFxAWyAAuOAAAwFdC8BsA6CAuoBAIEC6gEDgARlAQCBB2uYBE4BCqMEToADYoAWkYMAaYAADIYAaYAA2wIHcYEAbIsCpwEEgADGhQKrgwBBARaDBpKAAAeABqCBHYyBAzWAAA6ABqCAA3AFEyAaIBuBA2wCIg6CASEBv4IQGYYBIQEXgQEhAcaEAmGCAR2AASgBDoEOh4ICSgNkIg+BAAcEaGohDIAA3AELgAVfgAEygB2qBCgCWHSAAsEBIYIVWwNQISKAAQGAGzWAANgBCoIBBQEigAM8AhhxgAnZB2oiIy0AASKAAwaAH0OBCuiBGHSAARWAAQGJAz8BCYEBFQEJhQM/gADXgAGfBiMvAQIiCIUVhoAI/oYBJoAADIABH4IExYEj5oEBHAIgBoMBHAELgRZXAX+FBm2AAnoEEGsOAoAFjIERpoAJgYIPx4YAjAEdowCMigBlAwUgC4IJuQJBh4sDswEJgAGTAQOAAvmAJqaBBmyAAgaBADOAJZSBAJiAJFiADqeBJqiBALsDIBFqgAAeAi8Bgg7HgBY6jQCXgBDOpgCXhAIbgACagAszgwIggAI2gABUggxfgAp6jABcARupAFwBB4gAXAEHgwBcA/8AcYAnSoAnkYECIgMEIAyAACkCC2qAAhSWARGAA92BBT6CBiqDAbgBBIEBuIEBz4ACYoMDIYQCyIAFowFsgBfAhAA4ggAUBC8B9ASDAW8ClAqKArcBFoECt4AAcYUC64QDAIEGrQIgD4wC8gGjiwLyggA7gARDAVyDBPMBcIADPoEGmYIC7oIAoYEC8IAAQwEfiABDAfGNAEOEBnGGBpaAAzSEBZGAAAsBDYMAZAHIhQWRgQNXAtA3iQM3ggNVAVCAA8qLAzcBDIABboAE44EDNwELiwM3gAP0ogG4AQuAAzUCIQ+AAvqAAECAKeKBC1oF/wFxQQ6BAEcDBiEMgACdAQaBAhoDDCAPgQBmAiEYgACVAQaAAcKCAJWCAakCIBiAAIQBC4AoGgF2ggCHAQ+BAIcBDIAY1oEB5IAAiAENqQMzgQdCggOYgABGAQCAAe4BD4IAnYEB6wEPgQZlgAVkAiAMgAXeAtA3gAAvAQyDAmwBDIEALwELgQC0gA/ZghUQAc2DAXMBEoEWJAEggSYchQZ9gAAJgCSoAtA3gwAbAsAAgQAcAwBB1YEH6YcBqoAAHAMCQcmFB0ABBIEGZIAB+wFMhQJmgg/ZAQiMAYaAALyEAO6ACFKiAO6CAkmAAMcBBoMAzoQHS4AH4gIgBoEBWoAOZAEMgQDxiwSthQLpgCr+ARCDCiQBEIEA7YQHFIAL3QESggBHgAkdhgJMAiAQgQCPAxAgEoEAggMSDBGBEUeCB5sBCoEXEYAB0AEKggdagAXPhABGhgAiggAYgAcIhAAYgB4mhwAYggASghMekABMgAE8hAA0AQ6ABu+ACX4BDYILfgJB0IMAkYYJI4MJNAEKhCvMAkQhgiKckgBSgADLhABSgCk1AwJByoUBnYABIwLUN4ArtoEAQAFcgwKRgQALAVSSAyYBC4MDJoICn4cDJoIbeqABsIICiYEGZIECmQIiD4MqJYIBw4IHloAAYgELiAMfAQ+DAx8BD4YDHwEPhgMfggOmiAMfpQIxiwMfhQI9gAIcgQO3gAQeggPHgACIASGADMmBAycBCoUDJ4kCQQEPhgL1AfGKAvWGAlqAKx0DAkHLhQFgAQ+ACT6DAv2CBWsBSIcDBIgBXwMgBgSDJtOFAwOCHyq0AwMBSIkDA4EAcpIDAYEApQHMhAUrhgMJgAARhAIlAQaAB9CCAE2ACsYCFyCADygBCYAB7YIbNwEJgRzFgAAaATCAJMKBAAgCzDeDELIB/IsGKwEHhABBATSAKtEBA4EA1oAADIAQmgEogBA8gwBEAWuCBy2CABaAACIBa4EG3oETY4ELR4EUkAMGSRuBACABEoEK/oIumoAAF4EvfIEBmIcLWQEJggs4AwkhA4ABPgMSIAWAAS2BA7mDA6mBBueBB/2BAUqBLfGAAOiAAHmAA8iBAE2AAWKFA9+BFQeSAzOAAcSEAQ6BDLaFABuJA9uAA0aEACKACFSIB0OIBBCBABaEDIyBEacBEIMS6gESgxK4gQ0RgyGKgRGGgAFBgQl0gApLATyHD6YBLIABXQQQIBdGgAhXgAP9gCmOgRHFgBgbgSYSgAARgCsVhBCQgBVmATiDBb6CGECAEieBFXkCKHSBGhuAEkiBEi+AAG8COCCBFbqCHL4DLCIFggAugRGgATCBASaDADCBKi8CLAuDAfWAALuBA6QBBIEBXANrIAWADLCCIrsBNIMeogEsgBHggwRwgAANgAHoAWqBDNaAACeBAd+AC5yAAAIFCUsiCRuALAMDJiAJgQBqgQHsgQz5gB7ZAgRrgCwwgABPgQEDjABPggANATSBKkKBMCaAAVSBAKsCCUeAGXKAACmAAniAAJYBCYEdYYENaYEpLIASZIIRrQIIIIIRrYAddQFrgAAWgRrmAReDETaAEu2CLRIBFIAAF4EVwIABVgEgggA6gBK6ghF/gAPSgSQKgABDBBtqQYCAEeWDER+CEMkBRoEAE4AStoIUQYEOFIEwEoEIgIAAGYABKQcgDUF7IA0bginigAemgAGpARuAAAgDBCATgAAIgAGoBEYbIRmDKJoB0oMIsgJ8IYANdwEUgyAgBhkLlAkBDIAUNIYSsIABIYAI0oAAB4ATMIADNIADQgEOggePARCCMn8DAkFAgAGOhyf4ggt1gDP2AQKBM/aBKNeBM/WABMABDoEgaYAhowEEgAVkgAYeAQ2BBXKBFK6AAEoBC4AAyYEgTQELgA3RAiANgQvkAQmABBMEDSALa4MteIAJigFNgS1SghekAwkgDYAMgYEI1oMAK4EAJ4ABlAEQgQBBAQmAABUBD4ARZwJyQYEjkYAE/YAIz4AehYAhVoIADwMMIAyGIayABHkDCBADgSOKgxlCgg3/gxk3Aw1qIoAAVYAAcpMAUAEIgwBzhCaTgSkvhSuLgQMygQBSgyEIggBSgxk8gABSBQggC0kNgShFgAAJgQA9ggZnkgBgAQ2GJu6AAlOBADmCJvCAArmGKzWDItuBADkCIAiFADuCACwBB4EgP4cwp4EQHAENgiISAQ2EIhKCJYyBBtWBAYiAMrkBcYABNYEii4EAooALlIEBRIAABwFrgASngAAiAwwhCoINN4MYLYAAEQEIgABhAQqMGcmBIrKGKPWAAB+BBEOABdaEJAiAADUBGIEUHoAAEwEMgRDehQBFigAmgAAfgAAYAxQiB4AWqgEMghnNgAAPARCBM5UBAYAAEIEZzQENgAVJAQ2ABLMDByIKgRnNgAEiggAwgANvgSLVgAAQAQqCADGBBU6AA56EAYaAERiBBkWCGayAAFEBHIEA8IAYRoIZrIEBnIABZ4EZrIAAjIAAR4sZrAEIiBmsAwwgEIQZrIAUL4QZrIIACoAZrAEKghmsAQqBBUABGIQAtYAAKIIA2QEQgwENgBB0gwDcgQaPggAZARSGABkBEoMO0IQBygERhwIFARGLAcqDAe+SAooBEoQC2o4ANIACEAISEIIF/4AH+QIHC4IAmIAov4EG3oEESYAYNoElbgMaQXyAK3cBDoQj/IAQVQJxG4IpUYEATIEQ+AMHSxuCADoGCSAOIAf8gDp4gAPHARCAAxcCCyKBBAKHF+QBPIAABwEOgAXHgAQOgAAugAz+AiACgwAuggZNgQZbhChpgAAsgQZbgQRTgxm7gAgGAhEDgCEKgQAcggUogAc7gQXbgQUjgAyvgBpCgBmvBkEYdHILCIEE6gUFEBALT4EZUQF+gQAzAxAkBIAACoIeRIAmMoEGaoEAf40XhYAAHYEgHYIAF4IGdogXnIEZCYAfi4cE7AMgARGACXWCACcBOIAA6gEAgAAEAwELEIQAIoQX4wFAjBfPBQ8QEwvSgRk8hyVUmxkpgQkUoRkpAbSHGSkBJ4EOTYAtIYABDYAKcoAGDQNIIgSAE8IDQQ9LghsdA0GB/oAFSwFyiBk3ghkvghk5gDYphRkygABGjhkyhgAUjhkygBlunRk1gRt6ixk1gAC0ihk1AcS0GTUCQX6MAWYBcYABZosAEgEfgAASjBlHAQaAGUcEs0QBI4QZRwEQghlHAReFAUKDGUcBDIQBioQZQIECdYYIr4IHYgEDggdigg5eAcCDByCAAAeBHKyBGQcCIR2AABeBGWSAGSSjGWSDGUyAECCDGUyCCA0BHIUZPAMOIRKJGQKBFIyAGWSCIbelGTbDAAKAAeaAAbsDaw4fghl2GzM0NTYKCwwNDg8QEQMCFBUBJAAmFxgEPj9AQYQZeQMLDCSGAAqBLf+AGXuDDkyCGYWCGjqDGYUBCoEH/oAOMYEAEgEMgAwhATKDAAqCFn6GAWICDDOBEHEBBoMFEYAKDAE3ihY8AQaLFjwBBoEMaoEQu4Eq1YAhBoAEswSflgJHgTj7gQBbASiDAFmAEFcBKIEGBYAEyoAdDYAAAgIQKIEDBwEcgA84gAAuAjsBgTEbARCAAEoEQQIQKIIgsAG1iBdagAQZgABiATOCAKsBJIE204ACXIAQYYADBIAFRQN0QYCAA26CLg4FakEfcEWCAyGCCMkDAEG5iwxwgABCAQeBFqkBCIMX2wGHgA7YjQAeAgR2gDJEgA2OghcSgRjLAgdNggDGAiIJgAcPAQmADGWDA9GAAn8EA09xDYAWoYAFroI6zQGuiw3pgRRtATKLAUYBNqQBRoIL3oAGmIISH5MAq4ABtgQHQYDAgT2ygAAdAdiLEwODAdMBJIQYaYEBGIIEMoE2pIEANoAqzYEEZIE1AYMAC4ABdwM6AAiAB0aBACsCOgCEPBSBAZqDAY+CHTUDAkG2hRNPgQjIAQaDANuDGXkDRQ01pQDbiACYgQ5WgQy/Ay0AFYIlBYsAlIIIjooAigEEhgCKAbeQAIqFAWWADBSuAIqAAPeDIs2CAXOBICeZAJiBAqyTASIBuIsAmIEAJAEUgAS/AoAIgQGnAQeCESGFAKmBAASLAKiABLyAKDyKAKiDGqyCAksBNoIaooI+yoATnoEAvIENLYAP54EI+YIDV4AAaIEAo4AFvIUArgEogACugBv8kQCuAgwohQECgQAngg2wARCAABSKAdQBMqcCr4AIEoECWoADh4ADj4A84IECc4QDlQQYdnJygwPpggh2ATCAAScBvo8BJ4EQXYMItYEInoAC7I8O+YARH4UO+QRBAiEXgAEShgRKASmMAGGDFIUDCyAdgB8lAg0vhB5egRorjBoQgBh4hBoQAQ+KGhCFAOyGGhCHAOmkHl6BHlaABjsCpDyAAE+BDHeBHW+CD/b/HmubHmsFqDxBsDyCJrYBzYAABIEACoACN4kebIAAGIAAEoIeIwEqoR5tAayAAFEBzYIH34IpNQEQiR5uigBMgAEtgh5vgQHXAaiBATCPHm6AAEKHHm6DF9SAEgSBGWgBBo0eKgEynx5jkwA5ASqBABmEHmOAGaW3HmOAAE4DBgwwqR5ZAQaBAH2THlOAKniCGMICDC2eHk8BDoAACgEOgh5PAg0sgA0ukh5CAQyAD7OBACkBa4AQSYseQoEEGIUeQgEngwQQgg/XgAQQASuoBBCSHjCBOZ2PHjKAAZsBYIAAP4AeMoEBjIIeMgQFQR5JgSYRAU2FB8aLHjkBJ4oeOYAI3IgeOYAVp4MeOYAZcIIeOYMYNgELgx45ghyqhB45gRryjR45gEVqgR45mAQpgBtWoQQpAQqBAGmABLmBAGmAAAyPHjmLAn0BCIAAxqYeOQIhDYoePQMqIhSCASWMHj0BJpEePYMKGoceOYEB4YARuIE9Q4gbAgETgxsCARiGFn0BBoIBBYEXXwETgxfcARmBF1yAHUOEF9yAAL2kHjkBGYEeOQEEhR45AQ2IASaAAAyFHIEDBSAKggEcAiAKgwEcAQ2LHjmAOXmFHjmAHcuAAn2CAeIBCIQXFQElphfnhwBlAwUgDZ4eOYAU7oACBoEAM4weOQEEggC7ih45gCAWjQCXASSoAJeEAhuAAJqAESSDAiCHHjmACpGNAFwBI6kAXIAeOYYAXIIeOYASUYQeOYADTgELgADygRWsAQ2bHjmCCCqBBQ2FAbiCBkuBAc+AEf2DBCaEAsiAEuqmHjkBJaAeOYUC7oweOYIAO6AeOQEeiABDjB45ggBDhh4zgQ9whB4zAwUMK4keMwQEQQZJgBGkA4ICSYIM4qYItYAFjAIOaoAFFAFrgBpEgQV9AhJrgSgZgRaegQ7HghaWAxwiDYEXJIADkoEWzgQgaiEhgAOXgAAMgxtzASKDAA2DA6QBI4EACwFUgAOkgAAHA1AhGYEABwFAgQLIgQ7VAQOBAAeBFiSAAAcDMCEkgga/AQ6BA3KFBrSAMLGAAAuBPs4CCGqAGK6CReMBcoIKfoEDTwILIIArtwIgI4ID6oE9IoRBSQEGgQP0gAzsgRmBAgR2gQQWgRuhggHKgBtmAy0AAoEZVYEjMYAcYIADBIADpoEK9gEGgRsuAQmCSTeADVWCAC6CBO2CA9OBECSCAJiBIY+BAt2CBk0BCogAqIIAnAIIaoAAT4IAeYABAgEEghqzgTyggBoRgACJAQuCA4uCAN8BCoYC/4EAC4YA34EdAIAA2IEh8oEA5gELggTJASKEAN+HANsBCIMb9gEIgQMUggDbgBbFgUsRAX+AAJaBALuERTiBDhSCA4iJA2yBBe+CEPGBPyiAGvMBGoMAgQEDhAAfgS8Dgg5MAQKAA2aBDumCAM6AIbSCAUeAASKCG42DANoBaoAFWAMMIB+AGP2DG0yAGkuBRIwBJIEbSYAB0AHEgRtJgBtHgAZqgR0mgRd4gQFUAw4gIIFFCoAD2wEEgBQsgBj6gS1iggGXghrsgwGXgiU4ggZ1gUKwgUSDghmYAQuBBcYDDiAhhQBBgRcRAQSDPf6kAEiAGriAGsSBAKmAFQgCIgeAF6uiADaAFnSBBI2AADQDayEJgRawAQ6BBHyJAMaBOwueAEiIAEmAAVgBCYEEmwQJQQNJhgKZgwA8ggHlATqAAZWFAq2AFTiBBWkBCYAAV4ACaIEAV4AAB4MHwIAVjIAg/4YAPAIJQYBCDIAXBoMC3IAMsYIAcIEjvQEMgByGgACrhAAogAAMhABkggAKggBkggBWgC6TgwYqgQByASKAAE+ASveCAGaAAnuBACqAAD6ABb0CQQKBChiAEFCEAGaAAOMFLQAEOgCBRomADh0BDIExmwEIgx5YgB5WgQECgh4YAwgMH4Ee+4ECR4EC04ICS4ARFIACS4MC4oAA0oII1YIhiIEBFQEZhwAshwNRhgAsAQuBCf6CIdADDRwagCGzgAAVgCiKiAE/gQNMgCBngBtJAU+AJLOAIq6BREyCLAGBCGYByJEjTIAD0ooISoEeZ4QjTAENgQN7gAabqwhKAiANhSNMgABAAgAigAZ5iCNMAQuCHZqCAt0BCoQjTAETgACVgAA1gyAtgRi+AQWAHAeAGtMDcSALiCNMgAo8hSAtpQCIgApagwPLAQuGI0wBDY8jTIEAWYEBG4wI2gENgiNMghT2hiNMgCf0AQiRI0wCyDeDABuUI0yCKCuGI0yCBLGAACGII0yATlGBCtGJAYaAALyEAO6CCsGlIEmAAMeEAM6II0wBC4UEvIMjTIABFYEA5oIBFYUH/IACNAEOgQ9pgi4RiyM7gAsbgQyKhANhgAGqghSSgR55ggd/AQqLEJgBJKQMiIAfQQIgDoI9TYwd1gEDgh3WgUXLgBl2gQeKAUaCB8qAEgGBIQKBESuCIoGBEb6BAk+AAb8BA4MUlIIAloAAN4AEroACXYMAGQEpgRaKgxSlhBCBggPagBF1gRFzgBoEnBEcggBnAhtGgAAxAwBB54oJEIAFVgMSDB+BD5eBJs2AABKAAMGAEA6AKq6DACaTEPwCvf6CHpKCFB8CAHGBSEeBDkOALOKFIL+ABHKCIKQBBoEBaYMAFIAAZo8AHpEAMoApPo4AFIIS+gHOhSRzhA8zgw9EAQaCK+SBJHMBCoM30oMOy4AA2IEANAHPgwK7gQyUhyRqgAECAcyLJGqCAZIBVIADV4sCvoAcdQIgCogkaocERKQqx4MDp4EdU4wkagLIN4MniYAcx4gEPYokaoEEPYAZ+IQEPYEH7IEeo4UEPaUAgYsEPYUDW4ABIYEIXIAFPAEKggChgB1qggN7gSgMhARFiQNfniRqggFgiyRqggQbgQ6lgRCXkiRvgAFkAiALhCRvhQQmqidyjAQmgyRvhAQmgyRviQDFgQ1lgACEiSRvAQ6BNXmAKbuAAMCHJGWCA9GBAeiCJGUBBYwkZYIJHI8kZQEShiRlgApCjSRlgQBEiCRlgAAiiiRlgSJpgCEwgyZ5hyRlgBymgSRlgQAehRFviSRlgBAliwizjiRlAQ6BJGUBDoIATYAFE4YkZYcn6ocDYIcoSocAFIYoJIgAFIAAPIUB84IE/YE4sYEBA4EIKgENgQAOgTvthQymgRKsAgN2gCGpgx33gAWWAWuBEa8BIoQMzAETgCOjgAh0gROzgA4MgAAsgEzkgBO4gQN2gQgzAQWCAciBDNSLG0yAAAcBBIEEfQFHgQT/hAa2gEMDgRMNgyTiAQaBVOKDFfQCQbmHEsUBFIAJFIMXJYIBXoA/q4ItF4ASxIIB6oIWqYAf3IAfsoEbpAENhAAKARiAAZ6AAAcBFIEBxAEFgQIDgAz/gAzZgAGWgCSHgRrrgB1sAwtLG4ES/oAAJoAKGYFE1JAY/4QXHoETKYQXyYUTLYEA9AFEhBMahBMogABdgFFygAC/AbqIEVsBRIYYMIEAxYEGtIEGqIQPpQFqgQPNAQOFAMeBH+eBRRoBHIFV44ICtgFEgAh4gAARASCBJK6DEjmBAHWBCDMCIAOCFQ+AF56CAkGBARgCSRuAAj6WGJ2GAMoBBYQAyoEAf4IT3IAOYoAAwoAhH4Ip2YQX+YEeS4Id3YAAxgG7kgDPgQ0BhQDPghUHlQDPASSNAM8BKOQAz4M2Z4kAz4EdCAJBvIkCXQEFgQH1ggTNhxongS8xoAhFgwCchQCRgALiAy8BHIFPNAMAQZqLCYGCF/OHGNCEGlsBQYA6dIAnNoAA8AEJgxuEgBJGjBz/jBi1gQRqgBRnggRoARSAAAiKCPqBQsShCPqBCKSBI66CA5IBIIFTEwMAQdCKBRWCAKWABemEF/iCALmDB6OAABsBFIEWxIEAqYMsSYEsWoFATaUQ6YQTp4EFYYE1BIAJX4FTlIMk4oEonoconQEIgQr2gAAQiSidggsPliidgABuATiBQ6WFKJ2DKMuNKJ2AAJsBLIEBu4IGL4AG0YEH2QEIgAWWhShQkCifgihCBDQiBmqAACcBCYAAJ4NYDYAAPIBVZIEh2wEIgAA4gRLxgiifgAAjgAUhgBAygCa0gSifgACWkyifgBAPgVXQgij8iyifgg9diyifgATcgyfYAQSBAYWEKK6ASmiFKKmCAM6VKKSFAqaHCs+BIV2AAKaDCrgBHIFZ6oMHB4EK1IEROwMIECiDJMqBAAsCKQuBLH+BAo6AAAeCKSyBBdq5KPMBBYAo8wEFgyjzAQWCAJUBG4FFgwIgHIYo8wEXgwJkgyjzAQuAKPSADMQBEIMo9AEXgyReAQeLJF4BJ8EkXgEKg0EyCA8QQAvyBgEFgQBcgQTNjiQogUBVhSQoAUGBQ/aAXRaAALUBBYEWiIEDwwFIgQUZgEOigylzARCBNXuBVy+BJqWAHJ6BBUkCEGuAQPaAXb2CThcCCEaBXG+BKX4CCEmBBA4CS3KAJB2AAPSFAukDQcgtgCV6gALhh0rxARyBI/KCAAeCPvOAAA4BKoIa9oQ+fwRC//+BghsZAVSAAAwHgICCgPABN4AJ1gIBQYEfvwIHG4FSHAEwgUB9gU7mgAAMASyCWrQBAYAIpQE0gwEYgSSUggE4gQNYgQNWhAAWgAFaASyJABmEAWOAABcBTIcAF4Fa44EAnQLELYNGpQFEgAAPAoCAgAC1AZyBABGCANOAAA8BQYIjVYIDuIJdC4JUaQKcLYAaGgECgAzDgCo0gABdgQHJgkbsgAJvhAAIAUSCBfyCRyoCQZqAB4KBQycBgIIVrAMAECGAJyOCQTKAAH0BiIAAUIEfAAGEgQGdgCDCASSDJHmAAn4BmIEAhoBOFQFsgBFvBDYCpC2BAeWAAD0BNYIB5IIBDYslW4MCU4MNY4IApYAAboBGsYEIY4AELIAB64EAcYI/D4IoKQUBQTlBKoEi7ANGIgKCVaiCVSGBAhGDBdmCJ9WDDZ2ABiWAAYaBAGYCvC2BQq6BAEkDOwG4gACgB0GIETYCuBaCAloB/IED0QGwgAAMAkH0gCi7AayDABUCiBOAABUBpIEAFQHggAAVAaCDABUBlIEHTwGYgQAVAX6BIoYDARArgwC9ggKsASyAFuqCJ/2BAawCAXSAGJCDWHsBRIBA4IMa4oE/doImi4NAi4EA8gK0LYABBoEmMQQgNwJ0gwERAWiHABIBXIMAJQFIgwSPBYQBQQxsgAEpA5QgaoAY6gM2ApCBKCgDAUGQhAAPAYyDAA8BkoQADwGAgwAPAZaEAA8BfIAFFoUDfwFxgAN/hAALAR+AAAuMJjYBCIAmNgL2JIAs9YElZYFS9AIQNYEl7IAu1wIAGoICNYEE24QDoAEcg1GVgFlegwQNg05bgQRigwSsAQSAAkMBR4AvEIEA7gGHgQcDhS1EgSByggSCgAKtggvNgAK+gAKEhwa9ghglAhA3ggAsgwqagAWYgwS0gAraASiDRKCBAGmAYJ+BAW4Bd4Mn4wJLG4ETV4QAEAcDQQRKG2pKgAC5gBO9mCXtAwRBKoJUhIEArYNIDYAH7gELgjUigAKFgxIhAfGCCB+DM8QDMEEMgCT2AfCBHImBB7ODALEBiIAAhwFKgwmFAoQBgQNlAUiABGMBwIELfQEDgBizgAAMgAOSAcCBAxgBBoAEyYMfCIBS9YAAKQIgcoMM7wFsgSjCAh9wgERgBUEfcxA9ggATghuoBAAvATKBABCBAAkDMBA9ggI6gwLggwi7ggCbggEtgQE4hAfuglwYAkE5g1W5hAMaggAvgwmVgR0zgQNwggB6gBkEAR+CEhKTABwBi4EgGJUAHYAD+oZQp4MmxZMAKIINkOwAHIMGC4QBkAEJgAHjAUGASoqDB0eCAa6BOfMCAkiEAY6RAEYBIIAWAJYAYoELUI4BfoEJ+IQCooAC6YAIbAEkgQ55gQMpgA/AgSKGgA9ugAQrgQ4qgQhxgQL6hA2CggBdggCygAZDggB9gAoXAkdBgQQwAwgbcoIAuAEDgAAIgmGWgAAIARCBC8gCG3KCAISAAF+CCk+FAE2DH+mADZqEAEmDAKqeACaCJn+DACkDLwEGoABPAi0AgRcEnAAmvQF9ggC3gklEnACOgloYgVgqgQ5voQEMmQAmiAEMgAk4AQuAAbOCHG2ABBuAA0OBChqBADeCA1KCIQ6HDb4BIIJe9YMDgYIEWwHFgCpHBgUCCQkJA4IYBgHbgDQPgAVoAkHngQ+ngl3FggIugiv8gwNFgwTxAwMvAYAKZIAHwIERqIEAbYEEaIFHuIIqLoELIgFqgBmhgwCMgDIogwDSgjU4ASCAAL+BGg2GInmAFTaCCrGCACMCLEWBBHgBT4QdPYcA0IAARIAA6QFrhQDTggBJhBWrhgLcgRkggQ+OgE/XhR5OgwLrg0R2kACJAQaFAIQBFIFT/4FJ04cAh4AApQFNkQCHgQC9hgFagQFSghddhg03gAA9ARyDBhEBFIIkHIEAE4QBI4AL14EA74JKSoQA6gEHjwBjgByggAAYhQBjhgU3ggH7gABKhA2QgSSigQAQhAIjASCEAiOAARSAENmCD4WBBcKEAjeGALuBAjSBEmKEBRKBAIWDBhOAAt6AAIyCCl2KAIqAABaPAO0B24IA7YYARIIvLeMA8AEktADwsQDuAeeJAdOBA1+BAMyEANiAGuaCIQKFAK2BF0aDTy4BMJcAiYYAHpoD04kHDoEAh40FwIEs/YIC1YI6JIIACoITMYIACoFTU4MACoMAjoIvLIAAOAF0gQs8gU1vgQP6gAhHgTfzhAhfgg32gQUFgwcdAwEQNoIz5YUI6IAFDAEChSNQAQKBCmGBF1+FAB2BAFcDAhA6iABiggN7gwIrgAo7gg/JgQm6gAAhAVyBCy0BToFoKIEPJAIDaoFAiIEADAFsgWH/AwEQL4MAJgFsgiGlgAaJAxA3QYAFgIIAC4ADrwEbgwDagABWAWCDAECBACuGAfeAAA0CoC2BTHmAAVECoC2BTB4BKIAL5YkHgLAAH4MBtIEVloEXxYAPsoAKp4AAJIELKIIANIAQeIAMPgF0hAC3gRKygkLkggBOgQAGAqQtgAD7gxmelgD/gRQ8gAHrjwD8hQD4gmUIggEnAqAtghH3ngFKmQBOgAI9gwFIgQHHgicRgyU2ggDPgEnKAoMCghjkhgFnAWyDKSGBAeICAUWHACUCSXGAEyCAPG6LACqBJQCBEb2BAJWAGlKDEi6JAgqCMaTAAgqBAviDARCELou4ARABB4QU8YAAsoATQoIUzoIA84AEkYAZuYAB4oIh6oIZcoISkoIhuYYACoBZIYE21AGCgR7zgAkagBAqiQACgAUMgB+BgBTJgSHsAQiDVfOAAAyBWVaDAAqBUv6DAAqAAyaBNgSAAAqAC+GBZ3yAAAqAJF+AYVmBAAqAVcSAE8eBHE+BIkGAF3iBGWKBF0UFA0H6AUmAGvuBInYBDYIU7oJDmIAZcYEEE4AmiYEACoAB8YAXzYEACoFRq4EgPwEJglGRgSA1giFXgDOIgQAKgRRagSY9gQERgAnjgBfygADYgAL4hD1JgQcdggHrgAMsgRnrAQOAOH6AMz2CIW+CAziCAzaAB0aCK6aGA1eDBOaAAB+CBOeOA3aOAB+BAFqACBuCBbiBHwAELQCQIYADgYAWIAJBhIEjPooDh4AytYIyDIMChoEVfgKIE4IAHAGIgCikggKwgirTgQOkgwzCgwOkhA3YAqAtgRj8gQHqhQRIjwDMmwCtngDMgQAfgjL3qARChACchQRDgSZjuwRDgCF/gQDxghD0BQxsQZgggGyWAQCAN8cBC4AE9AF+gB0jgzU8ghFLgQoBAX2AOmaBOHaCADwBBoE1IIYKAIAFJIAE1IUGHYALJYAKOoByxQIBAoJdSoABfwK4LYMDqQG8gBHGBHRyIgaCEMyBFFkDA0EOgTaelAtJAQaXDMaBFLoCuS2DDMqAEzWFAF0Ca3aEAF0DA0ENghNlgAI3AWqAANEBNoAAHoIAcQMEQQq/AHGDEYyCAHMCQQmCAGeAR04BaoARtYEAZQIQLoMT3YMHroATQYFWzoIClYURXoQcJYFRDYIsQIEmIIENJoIRXoECAIU3zIAFIIIACIABu4MsrIYQWoIAIoIH0IMQt4ECEIIFY4ISewRMDQMagwhWgQHcgWs2lQDVggOUhAAqlQAjhQiAgA/OmAAmggAjAy0AM50AI4AAC7sAI4cAjwEKnwCPg1TllgAjggaOg14JgC9gixCsgwMqARiBa2cBSoQTAAEAgAOXhGBjAkULgji9AfqBKukCQXuAAYQBAYk/bAIQIY06fQK/AYFTloMWkgE1ixaSgQ7bgmfzmBaZgRTgnAAgAUCcACCwFvkBfYISjAHxgBecAQuBVLcFARACCwmCE3ICbBCBdF6AACcBbYEXiQcQQQu9CQEVgTmuAUCACECCBuICBkGBPW2DDfqAZOyDQCCADVmCat4BdIET24EAB4AGMoAmVYUE/YAAGoAamYINoIJbooAbd4AllAN/IQ6BJfyBRLiCAEKBLxiBAECBAFOBB4qETXaAIP+BAASBUiyAF1OBTfgBCYIAgwJBEIMGzoIAPIAQroIAPIFAZYMHEIEm5IFLxIEN9Icv04MoLIQAWAEJgQAEA0sbIYA9uYAMcgEBgin9gD/6gRN6gQDMgT7RggC5ggBBgR5JgABNgQBlAWuACRUCAE6EbDmAAAuAAiCBALECR3KAHL6CNXuAAnwBO4AnUoMAUoAA7YAAroMBL4EAW4cBKQEigQlTgQBChwExgVz/ggEzgWUFgjAggAANgTIxhQFBAkETgUSkBCIVIRaEBZUDAA4CgAusgUGjDCESQe4IIRZBrgghFYEWcwF/gAARAvANgAARBLANIRWBG7UBDoAh7oBDXYFkPwIBRoFkxAECgG7tAyACG4BtrYAEZAMPdCKAB0wDayEXgxIXgC1jgkSwgASOgScigWL9A3QhGIAKQwF/gRHogEKOhADEgEjigBRYARqANlsCEkyERhEB4IJAxAEVgUkCgApAgQAmgEVAAwYgFoEHd4Aq8IAgMYEIbgMiDnSALKiALZOASkmCI1gCGiCAYmCAASgBGoAcqAEZgD7jggdFAwYgEIABS4AAPgEOgylIgRPeASCBKeaAAJGAAeoCa3SDAWSAHEsCAXaCBzeAbnGAATGHAhWGAoqAAbaENQOAcK+AQZqBVrIBCIF1AYAAywFqgC3gAQaCIv6BAn0BCYJBRoEBsoIgbwEMgwongkkmAwIgF4BBjYEd8oMBJYEAGAUgDyIKIYA7QYcAy4EEW4EAtoAc7oEAtoEVdoET/QEBggLXhQCygWXtgl2NgEHmghd9gwCYAQCCcUiAAJiCAqWDY9UCIBOBAFaDXwaAKEOBAmUBDoEJ8YAY74YBiYQAB4MJzgEXgGfXgACngUC8gHDBgSpcgANFgAAEAUuCKaEEIAwbIoBLxAEIgACyARiCAXoBEYEBTYEBkwQGdCEQhDM3gUvwASKBMgqAAdqCAU6CL9mCAv6AMnABSoFxhYAg/oICVoECT4ICIAMgE2qAAkQD0wZLgwJdgAC3BNEES3GBcUKCZJuBQzqDAdQBD4gBzQEGgTA1gFa/AXaBATIBB4Ax3YAD1IEAbIECNIMDroEDywEAgwMRgjCPglHvgwMfhwOVgQALgQAIgQM+hSrjAw4LK4ABX4IBy4AE3oQjg4EElYFnW4EAB4MbBIJaUQELgwT4A2BB1IIE+ALKA4J1T4RAV4FZywHVgRhOgRdCAdWABn+BdcOAAAmDCvuACgiBIRiDACKDT8WAEHeBKnGAAziBCmmANDWGN7mBDCWAG/+BAmiAADiACNYHQaCG4u1+c4ABCIEASIF1zoM0PoMFL4ELC4AJqQLATYk3RIAAaoEgSoNzEAFzgCRjgRyDgDH+AX+DArSCAOsDIANzgisDgXZRgAA+gRBtgAAqiQD3hQJjgABDgBi5lAAzgAKnAgh2gQAegALHiQAehwAZgALnkwAZgBtjkwAZgBDdkwAZgAc7kwAZgAMnkwAZgD+wigAZggDigCD4gh1khADiAwvCBYAHo4ABK4ED4IEb+YAIEoAdm4BvloEBB4ELDYAANYAA/4EDtwTx/wNrgRIkBEHw/wOAJHCCcpOACEKBenoDgIA8gAosgABfggAbAyAAcoEceIJ5BoEiRIQBeoMBWIYAUYFqsoNieIAAk4QB0YAAYwFwgABSgQeAgQBtgWccggBSgABQgAIvAtsCgSZUA0GwK4IusIAApIIOVYECcoMAToMADYE2toQAC4ENs4QACwEDhwALgAC3hQALgA4/hQALgRTyhAALgA7uhQALgQ1mhAALgEakhQALgA7IhQALgETLhQALgAQUhQALgEaThQALAQ6HAAsBD4EAC4FBPoEw44IDG4AlNoN4BYEA+YIafYIACYEBqQKwK4MBqgKwK4UCjYBl5YICzYAfQYUCzaQBU4YAWoEnrIQBz4EBMIID+YF07YQAC4FqFIQAC4ABMIUAC4F1yYQAC4FskoQAC4FqTYQAC4FwmoQAC4ABMIUAC4ABMIUAC4FDQYQAC4ABMIUAC4ABMIUAC4ABMIUAC4ABMIUAC4UBMIJmqoEBDAEQhAELgADHgjM1AnRygAFEAQuBSfWHCYiAEcTJCYqDWBiFAD+FCYeAELWICYaEal6BdDKCKCMEQcACNoEM45IAF4ADXAEMgRB9kAm7ggdbgDCmxAm7gClQgwm7ggDEgAm9gSRcoQm9gAhBgF++gRLVgWWZhAnAAw0CGoM/PJAJwYUBaMAJwwEUgAbbBQUiFCEVjAnDAoECgAk9CaAPIRVB4A4hFIIgNoEAEQEQgQARAQ+AOayAB2QBDJQJwQIEGoEAHQJ0IoBOxQFrgDYFhAnCAQyPCcIBFoQJwoAAgoAHn4QAxYAvcAFqgDKDARqAI5iCIrqBWFaDCcUBFIEAE4ATpIUJyAEOgAF4ARWJCcgED2siF4UJyAEPhQnIARaRCcgBDoMJyAEX1gnIgRIKgDc4iwnIgXq3iADrigkmARiGCSYBDI0JJoEwlwQPGyIPgwkmARaICSaAAPGACSaADLqECSaAA8GCCSaANKyYCSaICSQCEmqAAaYB1IYJJAMSQdCCCSQCBxqNCSUBDKEJJYABkYgJJYADN6oJJoEFcYE5tYIz/ocKtoIBpIQKtoYKhAEShAqEgRKCgCfzgAAtAwsLq4ASC4EHWoEWX4E15AMBQZ6CEl4BAIEiroN9h4IAFgEegwAVgCLYiAAVAROCBLOBB1KAAFmEIpCHBdaAATEDOwGUgHAigQ6yAbCBIpWAIooBqIAACIEAEAKgLYEXGpIAOZYAGQMLrwKCAK2BEAmBEkiBDxSAEloBBIASt4BApIAAEoEjtgEEgxK3gg9AgRn2gxBagiS4gBBaAQWCCkCTAByABvyDEkaCZsKEAF2AEreKErWBNfeDEk4CABCAAASDAEqHEMCDAEqCOTmVAByFESWVAB+AAvwBc4MVTpQAqIYeSYMQNIQoQIEP/AEQgD4jgwA1gHE5gURHAaeAE+qCSzWCAMyAJkqIARuBAViEcYWFAP8BuIQA/5UAIIIBH4MS14ASyZkAKoIASoIiVoMBmYEAgIJsZ4AB+4EBPIIUioE9A4EAOgTALQumhQCpgQHghACtgk4TvACthQCCglE2gQpZAUiCcVOeAFSBAD+HALqAComCAfQDCwuBgWv6gAZWgEQLhQX7giVFghKIgQw9ASKALsCAJ26BGCeDA1UHCUH/gP+ff4IMVQEFgH2vgiQVgQxugUXrgQLmgQc5ghXGgAU3gSUsgRuvggZlgniFgALqAQGBdC8DLwG8hAAIAciAAAgCQSCDDKWBDJKAABaBDGSBFxiCDGCBB1iCEYWFFkaBGDaELM+AGFmAOzWCLLWBARsFmBZqEDCCAAoBpIYACoAAtIEAyQScFhAxggAQgAQHgQAQAaiFABABsIMAKgJB/oAECgMGQRKDHFuBGK+BBneACvuBAWiADQkDLQDwgEWsgwDegwpFhDJMggF9gAQGgAAygBfcAwZBEYABhIEEFQYoAqwtQQqAIwOAXQCABPqAKoyAAAqBey+BABuAHNIBBIAPs4FFhIAFj4IeyIEa3oFSzgIES4QenoImbgIQLIEAgIIEIIMT54ACd4AZp4QAIYAVcYAW4oA5IAJyIoBKoJIEMY0CFYkDy5cCZYEJyoUCuIQEMQEBjwQxAkGggEVwAxoQMoICi4EmSoQAjYJ6+4YAh4QAmrkAj4QDQQENgS5ZgQCagACUggqThDq1hFA2gQCTgQHpgTGrAf6BOyqDAeiAAWODARcBDIQAkIEykocBMrgAmIMH2IkBKoIqdgELgytzgwBngAASAQSAArGAPHSDAKGAAIoBB4cAioAKE8IAioBBIpkAioIAZ4J6nYEAioMBKwQFQf3/gwElggEdAQ3NAR2RAR8BIoAKeYICSwEMggCZhwBvgwAYgCT9iACfgj9ohQOYhH77gAk/gwMdgAtFigOUgAqChwBInwMGAQejAMKBGe6PAL2IAwiJAK2GBA+BBHOAAJADCRAzhQRxgCrlAQiCAA6BINyATPwBAIArFYEZi4AHcwYLC6ELARKBDUgEIGsiD4AuWoJ5YYBloIIXpoINEYEYBYEl3YMq8wLQx4AIdgHQgksSgQAEAUqCh20DQdgogw7jAtwWgVnUAX+CIq+CbMOCbmWFgjsC0CiBcdWBKYKCEGmCf5+AAEuBNQuDPZiBMvSAAFiACfABSIFY8oJ934FGvoAfdoCGHYAI/4EAwwEEhBx1hAT6ghxCgQUBgX2UARuBDN+Cci6DBQKCE7WAOCWAACMCrC2CCQ2CCqWDCd4BCYABuYUBpAHQgC5jgAuahACQggpxhH5ehgBwgG+dgjAPggoUgQYIgQnjggF1gnbjgR/pgAZzggD2gAfPgwbAAtAoggARggDvgACEgABdgAAVAuAWghTmhAD3gknIAuAWgAARgA1yAhA0gwCPAdSAAI+CNV0B1IUAMoIfMYIAl4FzSo8AJoUAHoQBNIIdcYYA6gEFgQrpgAuchgD3gg2PghE+gSamgR/igQxiAQSCAAqAGkWBHu6AAN+EIf6BCwOAMQWDCwqAHwSIAK2ER9eJAdyEBpODAJyAAI6CAJyDAeGCAMqDDxYBvIACKYAwNYEaE4B22IECaAEJhgJ0ARCDgBUBCINfQwEEg1KRgkfVgjg8gApNggOGgjluhkiahhQigjWOgVs4gwCFgwFihQr/gDT4ggn3AdSAAK6AAJUGvARMGyESggKfggHPgR8CgDONgDWxgTLvhAA8g3bngANGgVYngFZZhEAbgUeogQA1gQcpAUyALucBIoIXl4GH94EUsYEFeAIgDIIM74IX9ose/YMVBAIgC4EEI4BMF4FaOIMAbINwYYMH0oAAaYAAfIABpgMQamyDB9WAN9iHAtqAIPCAFl6AAIaAAcSBACCDAuCBCDyBJeKBSw+AAHaCSMABAYIChIF4DoE1HYEAtYFAV4IO54EI1YAASIE+X4IQUoNMo4EBHIEArAECggIngmOYgQ5ngg/DA0ECSoAA3IAAB4I564AAP4EAYYEAmIQAcoEOTIIDBIIUAoM76YIw0IMBS4EBFIIOWIEBVYAf7oEBRoAVbIJL8IQA+IAAFIEIXQIFa4QA9oASC4UDcYUTFYEK7oAMxIIW0wMAQbqAAkyBAVOBEJ+FAiGCEMaBPlwCAEiBAsqCBJGCDWWDELCBaoGGAICBBQsBD4MCTYEwJ4IFz4YBqIKGJIEAfAJxcoEPi4F+XoAAKgFLgj5ygQPvhTvzAQaDhO2BR+eCAKCFDbYBD4AOaAEkgBXIgwBhgIrAgRyTgHLqgQOFgQARgAbqiQK+gYlbgAO2gANbhwDvBQu2AgEJgBd7gTztg41agQLOgAbdAjsBgEMMAUGAAkqABPcEQQdBioAzCAEbgQhvgg5XAQmABYeAVASBHhSFAQWBQfaBAZyAHYeBIVODEzSBA2aBEBeDjw2DBZeFAuCAMCSBNzeBDzcBS4EQfoAG2YA8koEn94AEEIMEWgEgggRcAQaDBFGCIIeCFj+CdQiLACWDAVOCAuCAC34BFYIADwK8FYNG6YETagEJgnkvgQAdAcCDAB0BwIEbtYMAEgHEgwASAcSAG7aAEWmAI68BQYAtpYCECgMiAxuFAPeAJSKAAy0BG4QBD4IBOALZCIABOIMGe4AlLIEAXoIKyYQO6YRQboEADYAi6oEV6YAVDIJ+SIEHwQIDL4AFCwEHghZzgwVaASKAA7+BFouCAJCBDsKCEtqEB6CBB/2AAY+ADRmAEkeANx2BMxKVDm+YDq6SCwIBBIAH/IIAXIEsFgFqgBUPgQyGgQALgwr4gAiHApAhgCWpgASkgTdNAy8BhoFNloUApoAAEAKECIA8B4MASwEGgACngExBgwikgABhgBduAQaIAKuDI/2AG/mEAI+CLd6UAMeIAKsBC4YAqwEGgACrgwBggYB4gQCrgjfqAQaACKqABjgCvC2BB30FQRxrQWyCPzGDDN2CfA8CkB6CViOCAJWAAA8DoBsigTyigwCbgQ2CgSNLgwEEuQFWjAoSgBCMgjy2gwFVgibzggBqhAAVAQuBB1qCD12CANOBAyeCR1KAXtmATBiADiuBCLIEgQJJG4ABgQEjgwGBgRhEgQImgQffgABFgQIigADhhwC8ggDgAQaAYdyIAXWHKwWqAiCHAXUBBYYCIIGEHoQAy4EAC4UKHwMKQQSBXyiACNeAAWkBH4EzEoBVpIABZQEcgAGwhQKrgADxggrCvwFlgQYkigFnkgCgjQBygQiHhACwgQljgBiJgBLpgQO3gUc8gALnAy8BgoGKO4EAN4AADAGAgXbKiACvg2HAiwN4tAFYgBEohwt0gwtygYycgwC2gQkjgxC6BbMLAQp/gwV0gQWYAiIHgDEmggWMgAAJgRCrgQWCgCHRiQV+gSCAgAxGgQWEgxc7g0nagQV6gxfpgUj4gwV4gAGrAUaBK4aCBY2DBXqBC0yCQZyBb0yBFX2AAGaCBM6CAZ2ABM6BFi6GBKOEAn2ASJWMA/KAA1elA/KNAByIASWAYOWOA/KOAn2ACqiBJiWFHk+BV9+HEE2GBYSBDpGCIFWAC8CCJ4eDRFuEAOaBCroBAoQB+IEGRIE/E4UB94Aeg44B9bICsoIkJIEEEIEAwIISNIEFGoBMeoUB84gP44KAZYEGv4MAioEq8YEBDAQvAb4VgHothgNOvgNGiwCUgnwkjACUgAYFgAAnggFkAQaDD0yBHScBD4RfAoEpgo0PSI0B0YkPSIECa4Ivrp4Dz4B7E4MoFIFUkYAFE4EGjoYAcYQAGoArdoEAGoJOwgEGgwfZggE3AcCOATcBwvoBNwH+hQE3hA+t4gE3gA/AkAEzg1K8ggEmAcSOASYBxvoBJgH2hQEmgipQ5AEmgyptjQEmgCp7gRkwgUaAhACgAQuCCgyALh2BPGuBBY+AGvqABYiACgyAAA+ALlyBBY8BCIQKEAL/AYCcDYMQroEJuoEQroGVtIUMnYBRMoAMGIFOZ4MNOYMOFoCaxoEAnYAO4AEEgAy7gkdXAQSAHS6CG0WAAWKABV+FAECCBLKBBKWChb2HDkCALxmDABgBDYNBZwENgSqmgAtIgQ9ughChgAAIgkHkgAuYgw1tgT8LiQBCggBjggBagXxpgQDtgQYJgQA/hA+/gX2FgQEpgg9ng4N8hA0rhQAVgCm+AwALg4EanoANJoKQHIQ8IIF6a4EACIVj8IApqYQ+Z4AAD4ArbYM+g4FA1AHbgBvEBAFBFk2AK+6BhJIGQYGggAJxgCfigQBNgzdEAwECAoCf14ENlAIqRoAABYAzZYFj4gMAQTmBLTSBBvmAAl8DC9wJggGGgZUMgEaYggIUASyBLCmABt+AdsaBAA+AAAOBJCGBK+2DH4yBHniCABmDklmEAsACQSqAFtUCdSKAfX2BAbWAAkiBABcBbIMK7QFcgCXQgAGIgX9BgQ97gASOgQBrgABkgWYhg1pvAU+AEmEBS4EW+IAGbAFFgEB5gIQEAnJygWhggizPhD0igIIIgG54gCzcgQK6ggLOgF9ngB1nhBYYhQATgAtJhhqJhwAWgZgHgCRMhBp+hwAYgB2ohjTrgy6pgEk9hISBgQEYgQAIATiCAMaBHKqBALcBCIFH64A3qYMBBIKR4YI3+oKMw4E3zIEv5YGM34E5WoIAGoGQq4EAQoIADYFV9YA4FYEBf4UZWIIcxIA1zAIQOIItQIcAEYIAVoIADYEHXoEAVoIADYUbA4KCTYIBY4FdDYFFzoEXbYKD4YOCUYEBhIICfIIH1IIuBIIB4oIzWYJAXYEcvIEA4YEhcIKZK4EA2YQAJYM/b4ED2wFsgwBDgAAXgj+wAWyBbOwBA4KdDoEJGoBEfIE0a4EASIEDw4FIyoFEuYAAEAGwgARGAUGDh+KCCUGBAHCCALCAAEKBAAcCtC2BRFeCB88BtIMAGYAAioISnIEAA4ENE4IBaYIAMoABPYEAk4AAaIMFRYICBwG0gQ2TgUsqgJYlARuClCKCAEiBALQBXIEFP4AAIwLELYEfAYIAEwLELYEAxgIGBIM0ZgEBgAMkgaNohAFCgTaegSIcgQKhgQGtgBp9hgD0hQE6gQAlggCygQLVggrNgEXVgCphgQBfgTpEhACggToagQHphAESgQ4ggwFZmAESgEvfhBO+AWyDA1SFARyCAYeCBo6EA3SAQD6DAPCCES2CAUiANoGABm+CAj+tASyQASSEAQGAClCAC7mEA8uCAwiFA+eBAQ6BkH+BA7eCAICBBDSABYsCSxuDIaCADBgBRYUDtAEGgGVbhJlwggFjg4csgwCoATiABTGCRWiDS0ABCIIh/IMwVwEagzHzgwGWARqCO4QBC4CbNIAAyYMDSoFGSIIBYYIvMYAS9AFBgF7IAQOBTOmAJ32CHXeAJKIBi4Eu/oEAJYBnnAIQLoRBKYNCZoBvQ4EaqIGYvoQFbII5TIAaUIUCcYAVC4IDf4IvyIAAGIAADYFIUIEENoIADYQD1YEagoOFXYIAXYFpZ4MAHII1mIIAFoFDoAMLC4SBHgeBADKAaCSCBEiBBP+CBAOAATuBA92CRS6CA4cCECaHHYGAOe0BGIEy2oM484IAc4BDpIAAJIFAzoQRlIUAE4Q6s4QARoAApIQH9oAEuIAADYFKfQULkAkBD4EHd4EhAoEZU4Edx4CXKYWBgYEALgN0QYWCXkABAIE3aIIAEYACswKGAoI9BIMwt4M59oE1c4QAbgFUiAPUATiABwSCAe+AQ4eBVVoBc4CEsYJDlIAwLIMCrgE0gB8bgxaCgFRvgxTkgQdQgAlMggNHghK+hAGVASyAAHmBSOACA2uBB22BAAIDAxA7gjX8ggD7gjVyg5FkAQODn5+AABOANPyDA1qBNLaBABGBNPyCAxaAAAUBcIAErYYJDpIAKoCLYYcgxZIAIoI2FIIGdoGIqIY2FICFnYE2FIQVsIMlZoFzY4FV7oFhUYEOf4QQrIFIioAX1gKQI4EIMIINXIoANoIAe4BE34JpBoIEVoIADQKkLYEUUYEAlYFJIIABgIMD3QKAAYUeJ4IV4IARKQFgggGIgR0QggEkAUiDB7EBbIMEXwE0gBflgQGMgDepgQGCg0nFAVSAUcGBAa6BLWGBAEmCAPaDYHyBAZQBC4QJHwMQdHOAUkqBDk4BSIJyGwEMgwHKgiPngxXCghgBgAGwgwDHgylhgQCRgilmgjU2hABXgHBzgDhmggt+gzcxhwS6hAB3ggQhgAAPgVhzhAJDgwJsgVi4gwGOgQJegQAZggBNggsyggA1gQBJhDdGlgHGiBq4sAAfgwvcgVaKlAG9hDdMgwDVhwFMgjdLggHLgp/mhAe3hATVgaZBgTdQggDEAQKDN1CBBBuCN1CDAEqIBPWBAAeDO5OCniKDSO+BBjyAAWQBT4BH6YY65oIZhYQAYoJtl4QAYgEBhDqagZs6gTrnjQBigjrnhABmARuDRocCoC2DOpShAFOZALWBRveBSoKBht4CvgWAEb6CA+yAC7WAA+6DCneAiVeDFg8BPIMC5YAEXQFqgRjmggAdASyFoV+BB2CBEbKBmdiAEU+FBbsBcIAKYoFii4QCU4AKb4MIoYIAsYIAHAFcgwSKArQtgj83iAiAAUSBAAUBTIEeCYAMeIMLEIIAioABVYIKtYMWaYF1f4FEWQQgCE8bhCXIgAuPhAmMgk9KggA+AQOCGOelADuAEXWADduECHSAS1yCR1eBAlCDBYWDAWICBGqABzIBEIIC44EXB4ACZIMAMIEH3YGgiYAFlYQCg4EIeoIA/4EImIAed4IcWYcDRoENGYEDSIIEGwFYgBaOgAWogC+2gFTsgRAygR9igAB+g3FagkDRgACGgAAkgCj5gwAmggDogAAFgBkciAXOggE3ASKAVgqCBAeAGTyDAxGCGuuCAWSEHaqCHO+DXFmBL+MBhYEACoQCHIFAI4UJeIMJdQHEgAOAgiMsgyVAggEJgCNfgAQDgWQKAYKCLX2CAWGAAAyBDEiACHuADCqFTlaBApWBKoeCOOaBFD+DJS2BPE2AAA6CqcKBCd+BGXKCCeaECBWBMV+FAEGBSpCFSoWBAI+ACuSAAEOBFH2ACS0DC68EgB+0gQAZAXyBGVyAKQWBAAwBeIMBfQKMAYUNRwFshAt7AWuAAuOBGdWBAVgBA4Bl8YIFjAGQgJlBggDbgAGVgAxggAA0ggWcATiAHOaABQCBFtkBaoAFoAEHgj3agSsbgRbbgQTfg1v4gQAKggCaATSAHZ6BAZiDHUaBCuKAYcSBDAuDAC8CIAqBCJKEADICIAuCCJ+BAAqBXhGEAA2AA0qDPlGBPj+DEjyIajmGPkaAAICCAC2BBYmBPheAAA2AB7iCPkyAARyBMVyAAA2AOn+ADByBMVCAAA2ACdOAAFCBMUSAAA2APlWAAa6BMTiAAA2APliAAYGBMSyAAA2CFHaBBVaBB0iAEBiCD1aALtSBPl6AB5iBINiDPmWAPVGAAKGAir6CPmWBEIyDiayAY1eBAAqCQFaAHf0BBoNGMoARRQEGg6Vdgl81ghzAgADbghTdggKRgl7AgHHzgQJDgQ6jAQWDKAKAAuqASmABIIIjEIEZIoKdrYM9oIAC3IArXYMBe4AAG4FXcQESgAFwARGCAw2BA+oBAYELvoEsPAIiCYEC0oEZW4EABAVJGwu4C4EcQoMJg4EqQoEJg4RiuZIJgwFFgwIbgQmEgEDrgAFhgEM5ggtEkQmDggJIkAmDgAQqhAO1ggAZiQmDgx1tgQe8gwmDgAG2hRwcgQiBgAd6AXiEBVeAaSCCSXKCDjoBYIEcXoUAUAGAggDvgQLhggmxggR4iwm0gAP/AWCBJP+EA+qBSNSDKDCAAiiAPKyDFzuECaMDQYEggQDZiABsggLgAXiCDzWBCPiAAm6FZNCAABiAB6GDE1+DB1wBdIJZEYAACYUJ+IAQZYAABwFkgA/+gAHciQfXiENlhAAvhhALlgAigACAkQn9gBdwjgn9gR1ztAn9AXiBHfiCBTSEAXyAP5eAB6aAAIyANXGBCmqCWd6BAN2DBqWAChuCAOWAChsBCoMfJYIBE4MOBYAEAoQdz4QCJ4EJV4I1AokCIoAMppUF14JtpAIiCIQF14AEpIQCIIUF2AJ4IIKTC4QCF4IJ0IBPloEJHYKn2oAHgoEEfIECtYEABIR3xIZAP4QAkYIIOoFa0psI74KpJoAACgFohQWeggYOhAUHgRidjAIRhQIKiwnRrQAfgxJlgSBojwGwhwnUgwlthACFkgDghAMZkgDjhANygQouhgiuhgpIhgD+AQSCpeCDAWGUAC6ABKiCrdH/ASWHASWCAhSICqeBEEGOCqeGAhqQClSBB+WsCqeKAm2VAFOgCqeBBHaAk0wDAAs/gg/CgQAejxdIhkAhlAAfgAAcglJFBARAED+AAZ6AtXUCCxuAAA+HeJGACHGBLnwBSIB4CwQQGwtDgxYdh1XukRYdggogghO6ggfBgRIcgRPEgAcggXXxBQsL4x0LgVSNBAuhBGmAtDcFZmZpY2mAs7wBIIO1sBMAMS4zLjEuMS1tb3RsZXkAaW52gLREFWQgbGl0ZXJhbC9sZW5ndGhzIHNldIYAHAVjb2RlIIkAGQ91bmtub3duIGhlYWRlciCAtKoBZ4sAMgJkaYC0TgFugLTgigAWA2JpdIQARxAgcmVwZWF0AHRvbyBtYW55hQAXB3N5bWJvbHOOABgCb3KGAFOGACSFAFaCtMuAAF2AtRcBa4UApgIAYoAA+IAAmgxlcnJvcgBzdHJlYW2EAA2KANULLS0gbWlzc2luZyCAtX4ELW9mLYIAR4AAJQJjb4C1BAJjdIUA4wNjaGWKABeEAJiNABcEZGF0YYYAFYsBCwEggQDUBWZhciBigLVnAQCFAFcCcmOBAIEFbWF0Y2iGADIBd4C1ywRvdyBzgbXahgE7ggDeA3R5cIcAE4sBsoIA0I8AdYIAFoUBrwRjb21wgLX7AXOAtcCAAg4EdGhvZIAu/RMMC6UCAwAEAAUABgAHAAgACQAKgCXVDQ0ADwARABMAFwAbAB+Alj0VKwAzADsAQwBTAGMAcwCDAKMAwwDjgbhQggABAYCMAAIBgYQAAgGChAACAYOEAAIBhIQAAgGFhAACBZAASQDIghWNgK4cggCEAQeAAIABDYAAegEZgCX3ATGABD8BYYAARgHBgEXeAYGBReCAPP8EAQYBCIAl1gMQARiAAzcJMAFAAWABgAHAiQB4hQBwhQBoAYaAAAIBh4AAAgGIgAACAYmAAAIBioAAAgGLgAACAYyAAAIBjYAAAgGOgAACARCAAHIBEoAAiAEIggCAAQaAAQIBBYABBAMEAAyAAJaAGV0CAA6AAKIBD4CxBgQOC7cMtQEsgBmWggABARCMAAIBEYQAAgEShAACAROEAAIBFIQAAgEVhAACARDAASyJAICFAHSFAGyBAGQBFoAAAgEXgAACARiAAAIBGYAAAgEagAACARuAAAIBHIAAAgEdgAACAUCAAAIGoAgAAKANgACIgADQAR6AAAQBD4AAVAEggAAQAiAOgwDgAR6AAASBABSBAAEBoIQAFAETgAAEAQeEABQBDIABOAGMgAAEAUyAAAQBzIAABAEsgAAEAayAAAQBbIAABAHsgAAEARyAAAQBnIAABAFcgAAEAdyAAAQBPIAABAG8gAAEAXyAAAQB/IAABAECgAAEAYKAAAQBQoAABAHCgAAEASKAAAQBooAABAFigAAEAeKAAAQBEoAABAGSgAAEAVKAAAQB0oAABAEygAAEAbKAAAQBcoAABAHygAAEAQqAAAQBioAABAFKgAAEAcqAAAQBKoAABAGqgAAEAWqAAAQB6oAABAEagAAEAZqAAAQBWoAABAHagAAEgHp2AgC6gAAEAXqAAAQB+oAABAEGgAAEAYaAAAQBRoAABAHGgAAEASaAAAQBpoAABAFmgAAEAeaAAAQBFoAABAGWgAAEAVaAAAQB1oAABAE2gAAEAbaAAAQBdoAABAH2gAAEAQ6AAAQBjoAABAFOgAAEAc6AAAQBLoAABAGugAAEAW6AAAQB7oAABAEegAAEAZ6AAAQBXoAABAHegAAEAT6AAAQBvoAABAF+gAAEAf6AAAQBAYAABAGBgAAEAUGAAAQBwYAABAEhgAAEAaGAAAQBYYAABAHhgAAEARGAAAQBkYAABAFRgAAEAdGAAAQBMYAABAGxgAAEAXGAAAQB8YAABAEJgAAEAYmAAAQBSYAABAHJgAAEASmAAAQBqYAABAFpgAAEAemAAAQBGYAABAGZgAAEAVmAAAQB2YAABAE5gAAEAbmAAAQBeYAABAH5gAAEAQWAAAQBhYAABAFFgAAEAcWAAAQBJYAABAGlgAAEAWWAAAQB5YAABAEVgAAEAZWAAAQBVYAABAHVgAAEATWAAAQBtYAABAF1gAAEAfWAAAQBDYAABAGNgAAEAU2AAAQBzYAABIAN6AIArYAABAFtgAAEAe2AAAQBHYAABAGdgAAEAV2AAAQB3YAABAE9gAAEAb2AAAQBfYAABAH9gAAEAROAAMIFEwEJAJOAAAgBk4AACAFTgAAIAVOAAAgB04AACAHTgAAIATOAAAgBM4AACAGzgAAIAbOAAAgBc4AACAFzgAAIAfOAAAgB84AACAELgAAIgA2LgAQCgAAEgAAIAUuAAAgBS4AACAHLgAAIAcuAAAgBK4AACAErgAAIAauAAAgBq4AACAFrgAAIAWuAAAgB64AACAHrgAAIARuAAAgBG4AACAGbgAAIAZuAAAgBW4AACAFbgAAIAduAAAgB24AACAE7gAAIATuAAAgBu4AACAG7gAAIAXuAAAgBe4AACAH7gAAIAfuAAAiBA7YBB4AACAGHgAAIAYeAAAgBR4AACAFHgAAIAceAAAgBx4AACAEngAAIASeAAAgBp4AACAGngAAIAWeAAAgBZ4AACAHngAAIAeeAAAgBF4AACAEXgAAIAZeAAAgBl4AACAFXgAAIAVeAAAgB14AACAHXgAAIATeAAAgBN4AACAG3gAAIAbeAAAgBd4AACAF3gAAIAfeAAAgB94AACAEPgAAIAQ+AAAgBj4AACAGPgAAIAU+AAAgBT4AACAHPgAAIAc+AAAgBL4AACAEvgAAIAa+AAAgBr4AACAFvgAAIAW+AAAgB74AACAHvgAAIAR+AAAgBH4AACAGfgAAIAZ+AAAgBX4AACAFfgAAIAd+AAAgB34AACAE/gAAIAT+AAAgBv4AACAG/gAAIAX+AAAgBf4AACAH/gAAIAf+AAAiBBAoBQIAABAEggAAEAWCAAAQBEIAABAFQgAAEATCAAAQBcIIFVgMHAEiAAAQBKIAABAFogAAEARiAAAQBWIAABAE4gAAEAXiAAAQBBIAABAFEgAAEASSAAAQBZIAABAEUgAAEAVSAAAQBNIAABAF0gAAEAQOAAEIBg4AABAFDgAAEAcOAAAQBI4AABAGjgAAEAWOAAAQB44AABIC/A4AAdIECxgEFgABcAQWCBUoBFIAABAEMgAAEARyAAAQBAoAABAESgAAEgQYEARqCBeoBBYAD1AEFgAO4AQWAA5yATGqAAAQBEYAABAEJgAAEARmAAASBAAIBFYAABAENgAAEAR2AAASAv26AAqSBBkABBYACLIEFpgEFgAG0AQWAOroDGwtNgxx6hwAEAQKMAASBB1GJAAQBBIwABAEFigAEBEGwHAuAveGLAEuNADuFAC8BBoQABIEFiIEABIEBCoEABIEBkoEABICFfIIABAELhAAEAQyEAASABduBRGIE4B0LI4UAX4UFywIQEYAFbQYHCQYKBQuAN44EDQIOAYAHJQSUHgtphQCQhQCIhQCAhQB4gQBogQBcgQYfARCAAAQBFIAABAEYgAAEARyAAAQBIIAABAEogAAEATCAAAQBOIAABAFAgAAEAVCAAASBBr0BcIAABAGAgAAEAaCAAAQBwIAABAHggABvAx8Lco0Ab4EAa4EAZ4EAY4EAX4EAW4EAV4EAU4EAT4EAS4EAR4EAQ4EBPAGArwBBgE7BAgttgQDHAQSAAAIBCIAABIEBM4ECSwEQgAAOgwAMgZ97gKs6hAAkgQdzgQBPAQiAAAiBABiFAAyBCLeDAAwBIIEAlIAvUoEAawGAgQgvAQSDAAyAPCIKAQAQDABBkSEL/4Ah4AEDgpzlBQgJCQoKgEYggAABAQ2AAAEBDoAAAQEPgAABARCEAAEBEYQAAQEShAABAROEAAEBFIwAAQEVjAABARaMAAEBF4wAAQEYnAABARmcAAEBGpwAAQEbmwABARyBfrkEBAQFBYHCrAEHgAABAQiEAAGAWjqCAAEBCowAAYAkc4oAAYEBMJkAAYEBTJkAAYEBaLkAAYEBpLkAAYIDdYABzoUBvI0BqJ0BkLwBgAIbHLwAAQEdvAABgLyTgH3yA9AqAQ==")),B)});}
5980
6516
 
5981
6517
  /*
5982
6518
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -6026,46 +6562,54 @@ function _make(isCompress, type, options = {}) {
6026
6562
 
6027
6563
  return new TransformStream({
6028
6564
  start() {
6029
- let result;
6030
- this.out = malloc(outBufferSize);
6031
- this.in = malloc(inBufferSize);
6032
- this.inBufferSize = inBufferSize;
6033
- this._scratch = new Uint8Array(outBufferSize);
6034
- if (isCompress) {
6035
- this._process = wasm.deflate_process;
6036
- this._last_consumed = wasm.deflate_last_consumed;
6037
- this._end = wasm.deflate_end;
6038
- this.streamHandle = wasm.deflate_new();
6039
- if (type === "gzip") {
6040
- result = wasm.deflate_init_gzip(this.streamHandle, level);
6041
- } else if (type === "deflate-raw") {
6042
- result = wasm.deflate_init_raw(this.streamHandle, level);
6043
- } else {
6044
- result = wasm.deflate_init(this.streamHandle, level);
6565
+ try {
6566
+ let result;
6567
+ this.out = malloc(outBufferSize);
6568
+ this.in = malloc(inBufferSize);
6569
+ this.inBufferSize = inBufferSize;
6570
+ if (!this.out || !this.in) {
6571
+ throw new Error("allocation failed");
6045
6572
  }
6046
- } else {
6047
- if (type === "deflate64-raw") {
6048
- this._process = wasm.inflate9_process;
6049
- this._last_consumed = wasm.inflate9_last_consumed;
6050
- this._end = wasm.inflate9_end;
6051
- this.streamHandle = wasm.inflate9_new();
6052
- result = wasm.inflate9_init_raw(this.streamHandle);
6573
+ this._scratch = new Uint8Array(outBufferSize);
6574
+ if (isCompress) {
6575
+ this._process = wasm.deflate_process;
6576
+ this._last_consumed = wasm.deflate_last_consumed;
6577
+ this._end = wasm.deflate_end;
6578
+ this.streamHandle = wasm.deflate_new();
6579
+ if (type === "gzip") {
6580
+ result = wasm.deflate_init_gzip(this.streamHandle, level);
6581
+ } else if (type === "deflate-raw") {
6582
+ result = wasm.deflate_init_raw(this.streamHandle, level);
6583
+ } else {
6584
+ result = wasm.deflate_init(this.streamHandle, level);
6585
+ }
6053
6586
  } else {
6054
- this._process = wasm.inflate_process;
6055
- this._last_consumed = wasm.inflate_last_consumed;
6056
- this._end = wasm.inflate_end;
6057
- this.streamHandle = wasm.inflate_new();
6058
- if (type === "deflate-raw") {
6059
- result = wasm.inflate_init_raw(this.streamHandle);
6060
- } else if (type === "gzip") {
6061
- result = wasm.inflate_init_gzip(this.streamHandle);
6587
+ if (type === "deflate64-raw") {
6588
+ this._process = wasm.inflate9_process;
6589
+ this._last_consumed = wasm.inflate9_last_consumed;
6590
+ this._end = wasm.inflate9_end;
6591
+ this.streamHandle = wasm.inflate9_new();
6592
+ result = wasm.inflate9_init_raw(this.streamHandle);
6062
6593
  } else {
6063
- result = wasm.inflate_init(this.streamHandle);
6594
+ this._process = wasm.inflate_process;
6595
+ this._last_consumed = wasm.inflate_last_consumed;
6596
+ this._end = wasm.inflate_end;
6597
+ this.streamHandle = wasm.inflate_new();
6598
+ if (type === "deflate-raw") {
6599
+ result = wasm.inflate_init_raw(this.streamHandle);
6600
+ } else if (type === "gzip") {
6601
+ result = wasm.inflate_init_gzip(this.streamHandle);
6602
+ } else {
6603
+ result = wasm.inflate_init(this.streamHandle);
6604
+ }
6064
6605
  }
6065
6606
  }
6066
- }
6067
- if (result !== 0) {
6068
- throw new Error("init failed:" + result);
6607
+ if (result !== 0) {
6608
+ throw new Error("init failed:" + result);
6609
+ }
6610
+ } catch (error) {
6611
+ disposeStream(this);
6612
+ throw error;
6069
6613
  }
6070
6614
  },
6071
6615
  transform(chunk, controller) {
@@ -6082,9 +6626,13 @@ function _make(isCompress, type, options = {}) {
6082
6626
  if (!this.in || this.inBufferSize < toRead) {
6083
6627
  if (this.in && free) {
6084
6628
  free(this.in);
6629
+ this.in = 0;
6085
6630
  }
6086
6631
  this.in = malloc(toRead);
6087
6632
  this.inBufferSize = toRead;
6633
+ if (!this.in) {
6634
+ throw new Error("allocation failed");
6635
+ }
6088
6636
  }
6089
6637
  heap.set(buffer.subarray(offset, offset + toRead), this.in);
6090
6638
  const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
@@ -6107,15 +6655,7 @@ function _make(isCompress, type, options = {}) {
6107
6655
  offset += consumed;
6108
6656
  }
6109
6657
  } catch (error) {
6110
- if (this._end && this.streamHandle) {
6111
- this._end(this.streamHandle);
6112
- }
6113
- if (this.in && free) {
6114
- free(this.in);
6115
- }
6116
- if (this.out && free) {
6117
- free(this.out);
6118
- }
6658
+ disposeStream(this);
6119
6659
  controller.error(error);
6120
6660
  }
6121
6661
  },
@@ -6146,21 +6686,35 @@ function _make(isCompress, type, options = {}) {
6146
6686
  } catch (error) {
6147
6687
  controller.error(error);
6148
6688
  } finally {
6149
- if (this._end && this.streamHandle) {
6150
- const result = this._end(this.streamHandle);
6151
- if (result !== 0) {
6152
- controller.error(new Error("end error:" + result));
6153
- }
6154
- }
6155
- if (this.in && free) {
6156
- free(this.in);
6157
- }
6158
- if (this.out && free) {
6159
- free(this.out);
6689
+ const result = disposeStream(this);
6690
+ if (result !== 0) {
6691
+ controller.error(new Error("end error:" + result));
6160
6692
  }
6161
6693
  }
6694
+ },
6695
+ cancel() {
6696
+ // release the stream handle and buffers when the pipeline is aborted,
6697
+ // they would be leaked in the process-lifetime wasm heap otherwise
6698
+ disposeStream(this);
6162
6699
  }
6163
6700
  });
6701
+
6702
+ function disposeStream(state) {
6703
+ let endResult = 0;
6704
+ if (state.streamHandle && state._end) {
6705
+ endResult = state._end(state.streamHandle);
6706
+ }
6707
+ state.streamHandle = 0;
6708
+ if (state.in && free) {
6709
+ free(state.in);
6710
+ }
6711
+ state.in = 0;
6712
+ if (state.out && free) {
6713
+ free(state.out);
6714
+ }
6715
+ state.out = 0;
6716
+ return endResult;
6717
+ }
6164
6718
  }
6165
6719
 
6166
6720
  class CompressionStreamZlib {
@@ -6173,6 +6727,11 @@ class DecompressionStreamZlib {
6173
6727
  return _make(false, type, options);
6174
6728
  }
6175
6729
  }
6730
+ // These codecs are backed by the WASM module; they are unusable until setWasmExports() has run.
6731
+ // The worker uses this flag to know it must fall back to the native CompressionStream when the
6732
+ // module fails to load, rather than discarding a self-contained codec supplied through config.
6733
+ CompressionStreamZlib.requiresModule = true;
6734
+ DecompressionStreamZlib.requiresModule = true;
6176
6735
 
6177
6736
  /*
6178
6737
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -6330,12 +6889,15 @@ function terminateWorkersAndModule() {
6330
6889
  */
6331
6890
 
6332
6891
 
6892
+ const ERR_ENTRY_EXISTS = "Entry filename already exists";
6893
+ const ERR_READABLE_CONSUMED = "Readable stream already consumed";
6894
+
6333
6895
  class ZipEntry {
6334
6896
 
6335
6897
  constructor(fs, name, params, parent) {
6336
6898
  const zipEntry = this;
6337
6899
  if (fs.root && parent && parent.getChildByName(name)) {
6338
- throw new Error("Entry filename already exists");
6900
+ throw new Error(ERR_ENTRY_EXISTS);
6339
6901
  }
6340
6902
  if (!params) {
6341
6903
  params = {};
@@ -6345,13 +6907,17 @@ class ZipEntry {
6345
6907
  name,
6346
6908
  data: params.data,
6347
6909
  options: params.options,
6348
- id: fs.entries.length,
6910
+ id: fs.entryIdCounter++,
6349
6911
  parent,
6350
6912
  children: [],
6351
6913
  uncompressedSize: params.uncompressedSize || 0,
6352
6914
  passThrough: params.passThrough
6353
6915
  });
6354
- fs.entries.push(zipEntry);
6916
+ // detached entries (e.g. clones) are not registered until they are attached,
6917
+ // otherwise they could never be garbage collected
6918
+ if (parent || !fs.root) {
6919
+ fs.entries[zipEntry.id] = zipEntry;
6920
+ }
6355
6921
  if (parent) {
6356
6922
  zipEntry.parent.children.push(zipEntry);
6357
6923
  }
@@ -6389,7 +6955,7 @@ class ZipEntry {
6389
6955
  rename(name) {
6390
6956
  const parent = this.parent;
6391
6957
  if (parent && parent.getChildByName(name)) {
6392
- throw new Error("Entry filename already exists");
6958
+ throw new Error(ERR_ENTRY_EXISTS);
6393
6959
  } else {
6394
6960
  this.name = name;
6395
6961
  }
@@ -6428,16 +6994,17 @@ class ZipFileEntry extends ZipEntry {
6428
6994
  }
6429
6995
 
6430
6996
  isPasswordProtected() {
6431
- return this.data.encrypted;
6997
+ return Boolean(this.data && this.data.encrypted);
6432
6998
  }
6433
6999
 
6434
7000
  async checkPassword(password, options = {}) {
6435
7001
  const zipEntry = this;
6436
7002
  if (zipEntry.isPasswordProtected()) {
6437
- options.password = password;
6438
- options.checkPasswordOnly = true;
6439
7003
  try {
6440
- await zipEntry.data.getData(null, options);
7004
+ await zipEntry.data.getData(null, Object.assign({}, options, {
7005
+ password,
7006
+ checkPasswordOnly: true
7007
+ }));
6441
7008
  return true;
6442
7009
  } catch (error) {
6443
7010
  if (error.message == ERR_INVALID_PASSWORD) {
@@ -6471,8 +7038,15 @@ class ZipFileEntry extends ZipEntry {
6471
7038
  return this.getData({ writable }, options);
6472
7039
  }
6473
7040
 
6474
- getArrayBuffer(options) {
6475
- return this.data.arrayBuffer(options);
7041
+ async getArrayBuffer(options) {
7042
+ // this.data may be a string, a Uint8Array, a data URI or a Blob depending on how the entry
7043
+ // was created, so retrieve the bytes through getUint8Array rather than assuming a Blob; this
7044
+ // also applies the options (password, signal, onprogress...) like the other getData() getters
7045
+ const array = await this.getUint8Array(options);
7046
+ // return the backing buffer directly when the array spans it, slicing the exact bytes otherwise
7047
+ return array.byteOffset || array.byteLength != array.buffer.byteLength
7048
+ ? array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength)
7049
+ : array.buffer;
6476
7050
  }
6477
7051
 
6478
7052
  replaceBlob(blob) {
@@ -6514,7 +7088,7 @@ class ZipFileEntry extends ZipEntry {
6514
7088
  replaceReadable(readable) {
6515
7089
  Object.assign(this, {
6516
7090
  data: null,
6517
- Reader: function () { return { readable }; },
7091
+ Reader: getReadableReader(readable),
6518
7092
  Writer: null,
6519
7093
  reader: null
6520
7094
  });
@@ -6530,7 +7104,7 @@ class ZipDirectoryEntry extends ZipEntry {
6530
7104
 
6531
7105
  clone(deepClone) {
6532
7106
  const zipEntry = this;
6533
- const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name);
7107
+ const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name, zipEntry);
6534
7108
  if (deepClone) {
6535
7109
  clonedEntry.children = zipEntry.children.map(child => {
6536
7110
  const childClone = child.clone(deepClone);
@@ -6604,7 +7178,7 @@ class ZipDirectoryEntry extends ZipEntry {
6604
7178
 
6605
7179
  addReadable(name, readable, options = {}) {
6606
7180
  return addChild(this, name, {
6607
- Reader: function () { return { readable }; },
7181
+ Reader: getReadableReader(readable),
6608
7182
  options
6609
7183
  });
6610
7184
  }
@@ -6618,6 +7192,7 @@ class ZipDirectoryEntry extends ZipEntry {
6618
7192
  }
6619
7193
 
6620
7194
  addFile(file, options = {}) {
7195
+ options = Object.assign({}, options);
6621
7196
  if (!options.lastModDate) {
6622
7197
  options.lastModDate = new Date(file.lastModified);
6623
7198
  }
@@ -6684,11 +7259,15 @@ class ZipDirectoryEntry extends ZipEntry {
6684
7259
  try {
6685
7260
  const path = entry.filename.split("/");
6686
7261
  const name = path.pop();
6687
- path.forEach((pathPart, pathIndex) => {
7262
+ path.forEach(pathPart => {
6688
7263
  const previousParent = parent;
6689
7264
  parent = parent.getChildByName(pathPart);
6690
- if (!parent) {
6691
- parent = new ZipDirectoryEntry(this.fs, pathPart, { data: pathIndex == path.length - 1 ? entry : null }, previousParent);
7265
+ if (parent) {
7266
+ if (!parent.directory) {
7267
+ throw new Error(ERR_ENTRY_EXISTS);
7268
+ }
7269
+ } else {
7270
+ parent = new ZipDirectoryEntry(this.fs, pathPart, { data: null }, previousParent);
6692
7271
  importedEntries.push(parent);
6693
7272
  }
6694
7273
  });
@@ -6699,6 +7278,22 @@ class ZipDirectoryEntry extends ZipEntry {
6699
7278
  uncompressedSize: entry.uncompressedSize,
6700
7279
  passThrough: options.passThrough
6701
7280
  }));
7281
+ } else {
7282
+ let directoryEntry = parent;
7283
+ if (name) {
7284
+ directoryEntry = parent.getChildByName(name);
7285
+ if (directoryEntry) {
7286
+ if (!directoryEntry.directory) {
7287
+ throw new Error(ERR_ENTRY_EXISTS);
7288
+ }
7289
+ } else {
7290
+ directoryEntry = new ZipDirectoryEntry(this.fs, name, { data: null }, parent);
7291
+ importedEntries.push(directoryEntry);
7292
+ }
7293
+ }
7294
+ if (directoryEntry != this && !directoryEntry.data) {
7295
+ directoryEntry.data = entry;
7296
+ }
6702
7297
  }
6703
7298
  } catch (error) {
6704
7299
  try {
@@ -6714,14 +7309,15 @@ class ZipDirectoryEntry extends ZipEntry {
6714
7309
  return importedEntries;
6715
7310
  }
6716
7311
 
6717
- async exportZip(writer, options) {
7312
+ async exportZip(writer, options = {}) {
6718
7313
  const zipEntry = this;
7314
+ options = Object.assign({}, options);
6719
7315
  if (options.bufferedWrite === UNDEFINED_VALUE) {
6720
7316
  options.bufferedWrite = true;
6721
7317
  }
6722
- await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
7318
+ const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
6723
7319
  const zipWriter = new ZipWriter(writer, options);
6724
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options);
7320
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
6725
7321
  await zipWriter.close();
6726
7322
  return writer.getData ? writer.getData() : writer.writable;
6727
7323
  }
@@ -6767,7 +7363,15 @@ class FS {
6767
7363
 
6768
7364
  remove(entry) {
6769
7365
  detach(entry);
6770
- this.entries[entry.id] = null;
7366
+ const removedEntries = [entry];
7367
+ while (removedEntries.length) {
7368
+ const removedEntry = removedEntries.pop();
7369
+ this.entries[removedEntry.id] = null;
7370
+ for (const child of removedEntry.children) {
7371
+ removedEntries.push(child);
7372
+ }
7373
+ }
7374
+ entry.parent = UNDEFINED_VALUE;
6771
7375
  }
6772
7376
 
6773
7377
  move(entry, destination) {
@@ -6777,12 +7381,17 @@ class FS {
6777
7381
  if (destination.directory) {
6778
7382
  if (!destination.isDescendantOf(entry)) {
6779
7383
  if (entry != destination) {
6780
- if (destination.getChildByName(entry.name)) {
6781
- throw new Error("Entry filename already exists");
7384
+ const existingChild = destination.getChildByName(entry.name);
7385
+ if (existingChild) {
7386
+ if (existingChild != entry) {
7387
+ throw new Error(ERR_ENTRY_EXISTS);
7388
+ }
7389
+ } else {
7390
+ detach(entry);
7391
+ entry.parent = destination;
7392
+ destination.children.push(entry);
7393
+ registerEntries(this, entry);
6782
7394
  }
6783
- detach(entry);
6784
- entry.parent = destination;
6785
- destination.children.push(entry);
6786
7395
  }
6787
7396
  } else {
6788
7397
  throw new Error("Entry is a ancestor of target entry");
@@ -6799,6 +7408,11 @@ class FS {
6799
7408
  for (let index = 0; node && index < path.length; index++) {
6800
7409
  node = node.getChildByName(path[index]);
6801
7410
  }
7411
+ if (!node) {
7412
+ // exclude detached entries, e.g. clones registered in `entries` but not attached
7413
+ node = this.entries.find(entry => entry && (entry == this.root || entry.isDescendantOf(this.root)) &&
7414
+ entry.getRelativeName() == fullname);
7415
+ }
6802
7416
  return node;
6803
7417
  }
6804
7418
 
@@ -6880,6 +7494,7 @@ class FS {
6880
7494
  }
6881
7495
 
6882
7496
  importZip(reader, options) {
7497
+ resetFS(this);
6883
7498
  return this.root.importZip(reader, options);
6884
7499
  }
6885
7500
 
@@ -6899,6 +7514,10 @@ class FS {
6899
7514
  return this.root.exportWritable(writable, options);
6900
7515
  }
6901
7516
 
7517
+ exportZip(writer, options) {
7518
+ return this.root.exportZip(writer, options);
7519
+ }
7520
+
6902
7521
  isPasswordProtected() {
6903
7522
  return this.root.isPasswordProtected();
6904
7523
  }
@@ -6912,15 +7531,26 @@ const fs = { FS, ZipDirectoryEntry, ZipFileEntry };
6912
7531
 
6913
7532
  function getTotalSize(entries, propertyName) {
6914
7533
  let size = 0;
6915
- entries.forEach(process);
7534
+ const pendingEntries = Array.from(entries);
7535
+ while (pendingEntries.length) {
7536
+ const entry = pendingEntries.pop();
7537
+ size += entry[propertyName] || 0;
7538
+ for (const child of entry.children) {
7539
+ pendingEntries.push(child);
7540
+ }
7541
+ }
6916
7542
  return size;
7543
+ }
6917
7544
 
6918
- function process(entry) {
6919
- size += entry[propertyName];
6920
- if (entry.children) {
6921
- entry.children.forEach(process);
7545
+ function getReadableReader(readable) {
7546
+ let consumed;
7547
+ return function () {
7548
+ if (consumed) {
7549
+ throw new Error(ERR_READABLE_CONSUMED);
6922
7550
  }
6923
- }
7551
+ consumed = true;
7552
+ return { readable };
7553
+ };
6924
7554
  }
6925
7555
 
6926
7556
  function getZipBlobReader(options) {
@@ -6935,7 +7565,7 @@ function getZipBlobReader(options) {
6935
7565
  async init() {
6936
7566
  const zipBlobReader = this;
6937
7567
  zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
6938
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options));
7568
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
6939
7569
  zipBlobReader.data = data;
6940
7570
  zipBlobReader.blobReader = new BlobReader(data);
6941
7571
  super.init();
@@ -6948,29 +7578,41 @@ function getZipBlobReader(options) {
6948
7578
  }
6949
7579
 
6950
7580
  async function initReaders(entry, options) {
6951
- if (entry.children.length) {
6952
- await Promise.all(entry.children.map(async child => {
7581
+ const fileEntries = [];
7582
+ const pendingEntries = [entry];
7583
+ // per-export map so concurrent exports do not share (and lock) the same readers
7584
+ const readers = new Map();
7585
+ while (pendingEntries.length) {
7586
+ const pendingEntry = pendingEntries.pop();
7587
+ for (const child of pendingEntry.children) {
6953
7588
  if (child.directory) {
6954
- await initReaders(child, options);
7589
+ pendingEntries.push(child);
6955
7590
  } else {
6956
- const reader = child.reader = new child.Reader(child.data, options);
6957
- try {
6958
- await initStream(reader);
6959
- } catch (error) {
6960
- try {
6961
- error.entryId = child.id;
6962
- error.cause = {
6963
- entry: child
6964
- };
6965
- } catch {
6966
- // ignored
6967
- }
6968
- throw error;
6969
- }
6970
- child.uncompressedSize = reader.size;
7591
+ fileEntries.push(child);
6971
7592
  }
6972
- }));
7593
+ }
6973
7594
  }
7595
+ await Promise.all(fileEntries.map(async child => {
7596
+ const reader = child.reader = new child.Reader(child.data, options);
7597
+ readers.set(child, reader);
7598
+ try {
7599
+ await initStream(reader);
7600
+ } catch (error) {
7601
+ try {
7602
+ error.entryId = child.id;
7603
+ error.cause = {
7604
+ entry: child
7605
+ };
7606
+ } catch {
7607
+ // ignored
7608
+ }
7609
+ throw error;
7610
+ }
7611
+ if (reader.size !== UNDEFINED_VALUE) {
7612
+ child.uncompressedSize = reader.size;
7613
+ }
7614
+ }));
7615
+ return readers;
6974
7616
  }
6975
7617
 
6976
7618
  function detach(entry) {
@@ -6984,7 +7626,7 @@ function detach(entry) {
6984
7626
  }
6985
7627
  }
6986
7628
 
6987
- async function exportZip(zipWriter, entry, totalSize, options) {
7629
+ async function exportZip(zipWriter, entry, totalSize, options, readers) {
6988
7630
  const selectedEntry = entry;
6989
7631
  const entryOffsets = new Map();
6990
7632
  await process(zipWriter, entry);
@@ -6994,7 +7636,11 @@ async function exportZip(zipWriter, entry, totalSize, options) {
6994
7636
 
6995
7637
  async function exportChild() {
6996
7638
  if (options.bufferedWrite) {
6997
- await Promise.allSettled(entry.children.map(processChild));
7639
+ const results = await Promise.allSettled(entry.children.map(processChild));
7640
+ const errorResult = results.find(result => result.status == "rejected");
7641
+ if (errorResult) {
7642
+ throw errorResult.reason;
7643
+ }
6998
7644
  } else {
6999
7645
  for (const child of entry.children) {
7000
7646
  await processChild(child);
@@ -7049,7 +7695,7 @@ async function exportZip(zipWriter, entry, totalSize, options) {
7049
7695
  });
7050
7696
  }
7051
7697
  }
7052
- await zipWriter.add(name, child.reader, Object.assign({}, options, zipEntryOptions, childOptions, {
7698
+ await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
7053
7699
  directory: child.directory,
7054
7700
  onprogress: async indexProgress => {
7055
7701
  if (options.onprogress) {
@@ -7098,7 +7744,7 @@ function addFileSystemHandle(zipEntry, handle, options) {
7098
7744
  }
7099
7745
  } catch (error) {
7100
7746
  const message = error.message + (handle ? " (" + handle.name + ")" : "");
7101
- throw new Error(message);
7747
+ throw new Error(message, { cause: error });
7102
7748
  }
7103
7749
  }
7104
7750
  return addedEntries;
@@ -7158,9 +7804,21 @@ async function transformToFileSystemhandles(entry) {
7158
7804
 
7159
7805
  function resetFS(fs) {
7160
7806
  fs.entries = [];
7807
+ fs.entryIdCounter = 0;
7161
7808
  fs.root = new ZipDirectoryEntry(fs);
7162
7809
  }
7163
7810
 
7811
+ function registerEntries(fs, entry) {
7812
+ const pendingEntries = [entry];
7813
+ while (pendingEntries.length) {
7814
+ const pendingEntry = pendingEntries.pop();
7815
+ fs.entries[pendingEntry.id] = pendingEntry;
7816
+ for (const child of pendingEntry.children) {
7817
+ pendingEntries.push(child);
7818
+ }
7819
+ }
7820
+ }
7821
+
7164
7822
  function addChild(parent, name, params, directory) {
7165
7823
  if (parent.directory) {
7166
7824
  return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
@@ -8836,6 +9494,7 @@ exports.BlobReader = BlobReader;
8836
9494
  exports.BlobWriter = BlobWriter;
8837
9495
  exports.Data64URIReader = Data64URIReader;
8838
9496
  exports.Data64URIWriter = Data64URIWriter;
9497
+ exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
8839
9498
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
8840
9499
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
8841
9500
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
@@ -8845,6 +9504,7 @@ exports.ERR_EOCDR_NOT_FOUND = ERR_EOCDR_NOT_FOUND;
8845
9504
  exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND;
8846
9505
  exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE;
8847
9506
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
9507
+ exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
8848
9508
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
8849
9509
  exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT;
8850
9510
  exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME;
@@ -8857,8 +9517,9 @@ exports.ERR_INVALID_VERSION = ERR_INVALID_VERSION;
8857
9517
  exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND;
8858
9518
  exports.ERR_OVERLAPPING_ENTRY = ERR_OVERLAPPING_ENTRY;
8859
9519
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9520
+ exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
8860
9521
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
8861
- exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION;
9522
+ exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
8862
9523
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
8863
9524
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
8864
9525
  exports.ERR_ZIP_NOT_EMPTY = ERR_ZIP_NOT_EMPTY;