@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/dist/zip-fs.js CHANGED
@@ -50,6 +50,7 @@
50
50
  const END_OF_CENTRAL_DIR_SIGNATURE = 0x06054b50;
51
51
  const ZIP64_END_OF_CENTRAL_DIR_SIGNATURE = 0x06064b50;
52
52
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE = 0x07064b50;
53
+ const CENTRAL_FILE_HEADER_LENGTH = 46;
53
54
  const END_OF_CENTRAL_DIR_LENGTH = 22;
54
55
  const ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH = 20;
55
56
  const ZIP64_END_OF_CENTRAL_DIR_LENGTH = 56;
@@ -97,9 +98,11 @@
97
98
  const DIRECTORY_SIGNATURE = "/";
98
99
 
99
100
  const HEADER_SIZE = 30;
101
+ const HEADER_OFFSET_VERSION = 0;
100
102
  const HEADER_OFFSET_SIGNATURE = 10;
101
103
  const HEADER_OFFSET_COMPRESSED_SIZE = 14;
102
104
  const HEADER_OFFSET_UNCOMPRESSED_SIZE = 18;
105
+ const LOCAL_HEADER_COMMON_OFFSET = 4;
103
106
 
104
107
  const MAX_DATE = new Date(2107, 11, 31);
105
108
  const MIN_DATE = new Date(1980, 0, 1);
@@ -154,6 +157,7 @@
154
157
  chunkSize: 64 * 1024,
155
158
  maxWorkers,
156
159
  terminateWorkerTimeout: 5000,
160
+ workerStarvationTimeout: 5000,
157
161
  useWebWorkers: true,
158
162
  useCompressionStream: true,
159
163
  CompressionStream: typeof CompressionStream != UNDEFINED_TYPE && CompressionStream,
@@ -176,6 +180,7 @@
176
180
  chunkSize,
177
181
  maxWorkers,
178
182
  terminateWorkerTimeout,
183
+ workerStarvationTimeout,
179
184
  useCompressionStream,
180
185
  useWebWorkers,
181
186
  CompressionStream,
@@ -191,6 +196,7 @@
191
196
  setIfDefined("chunkSize", chunkSize);
192
197
  setIfDefined("maxWorkers", maxWorkers);
193
198
  setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
199
+ setIfDefined("workerStarvationTimeout", workerStarvationTimeout);
194
200
  setIfDefined("useCompressionStream", useCompressionStream);
195
201
  setIfDefined("useWebWorkers", useWebWorkers);
196
202
  setIfDefined("CompressionStream", CompressionStream);
@@ -205,7 +211,7 @@
205
211
  }
206
212
  }
207
213
 
208
- function t(t){const e='(t=>{"function"==typeof define&&define.amd?define(t):t()})(function(){"use strict";const{Array:t,Object:e,Number:n,Math:s,Error:r,Uint8Array:o,Uint16Array:i,Uint32Array:c,Int32Array:a,Map:h,DataView:f,Promise:l,TextEncoder:u,crypto:w,postMessage:p,TransformStream:d,ReadableStream:y,WritableStream:m,CompressionStream:g,DecompressionStream:S}=self,b=void 0,v="undefined",k="function",z=[];for(let t=0;256>t;t++){let e=t;for(let t=0;8>t;t++)1&e?e=e>>>1^3988292384:e>>>=1;z[t]=e}class C{constructor(t){this.t=t||-1}append(t){let e=0|this.t;for(let n=0,s=0|t.length;s>n;n++)e=e>>>8^z[255&(e^t[n])];this.t=e}get(){return~this.t}}class A extends d{constructor(){let t;const e=new C;super({transform(t,n){e.append(t),n.enqueue(t)},flush(){const n=new o(4);new f(n.buffer).setUint32(0,e.get()),t.value=n}}),t=this}}const x={concat(t,e){if(0===t.length||0===e.length)return t.concat(e);const n=t[t.length-1],s=x.o(n);return 32===s?t.concat(e):x.i(e,s,0|n,t.slice(0,t.length-1))},h(t){const e=t.length;if(0===e)return 0;const n=t[e-1];return 32*(e-1)+x.o(n)},l(t,e){if(32*t.length<e)return t;const n=(t=t.slice(0,s.ceil(e/32))).length;return e&=31,n>0&&e&&(t[n-1]=x.u(e,t[n-1]&2147483648>>e-1,1)),t},u:(t,e,n)=>32===t?e:(n?0|e:e<<32-t)+1099511627776*t,o:t=>s.round(t/1099511627776)||32,i(t,e,n,s){for(void 0===s&&(s=[]);e>=32;e-=32)s.push(n),n=0;if(0===e)return s.concat(t);for(let r=0;r<t.length;r++)s.push(n|t[r]>>>e),n=t[r]<<32-e;const r=t.length?t[t.length-1]:0,o=x.o(r);return s.push(x.u(e+o&31,e+o>32?n:s.pop(),1)),s}},I={bytes:{p(t){const e=x.h(t)/8,n=new o(e);let s;for(let r=0;e>r;r++)3&r||(s=t[r/4]),n[r]=s>>>24,s<<=8;return n},m(t){const e=[];let n,s=0;for(n=0;n<t.length;n++)s=s<<8|t[n],3&~n||(e.push(s),s=0);return 3&n&&e.push(x.u(8*(3&n),s)),e}}},R=class{constructor(t){const e=this;e.blockSize=512,e.S=[1732584193,4023233417,2562383102,271733878,3285377520],e.v=[1518500249,1859775393,2400959708,3395469782],t?(e.k=t.k.slice(0),e.C=t.C.slice(0),e.A=t.A):e.reset()}reset(){const t=this;return t.k=t.S.slice(0),t.C=[],t.A=0,t}update(t){const e=this;"string"==typeof t&&(t=I.I.m(t));const n=e.C=x.concat(e.C,t),s=e.A,o=e.A=s+x.h(t);if(o>9007199254740991)throw new r("Cannot hash more than 2^53 - 1 bits");const i=new c(n);let a=0;for(let t=e.blockSize+s-(e.blockSize+s&e.blockSize-1);o>=t;t+=e.blockSize)e.R(i.subarray(16*a,16*(a+1))),a+=1;return n.splice(0,16*a),e}P(){const t=this;let e=t.C;const n=t.k;e=x.concat(e,[x.u(1,1)]);for(let t=e.length+2;15&t;t++)e.push(0);for(e.push(s.floor(t.A/4294967296)),e.push(0|t.A);e.length;)t.R(e.splice(0,16));return t.reset(),n}U(t,e,n,s){return t>19?t>39?t>59?t>79?void 0:e^n^s:e&n|e&s|n&s:e^n^s:e&n|~e&s}V(t,e){return e<<t|e>>>32-t}R(e){const n=this,r=n.k,o=t(80);for(let t=0;16>t;t++)o[t]=e[t];let i=r[0],c=r[1],a=r[2],h=r[3],f=r[4];for(let t=0;79>=t;t++){16>t||(o[t]=n.V(1,o[t-3]^o[t-8]^o[t-14]^o[t-16]));const e=n.V(5,i)+n.U(t,c,a,h)+f+o[t]+n.v[s.floor(t/20)]|0;f=h,h=a,a=n.V(30,c),c=i,i=e}r[0]=r[0]+i|0,r[1]=r[1]+c|0,r[2]=r[2]+a|0,r[3]=r[3]+h|0,r[4]=r[4]+f|0}},P={getRandomValues(t){const e=new c(t.buffer),n=t=>{let e=987654321;const n=4294967295;return()=>(e=36969*(65535&e)+(e>>16)&n,(((e<<16)+(t=18e3*(65535&t)+(t>>16)&n)&n)/4294967296+.5)*(s.random()>.5?1:-1))};for(let r,o=0;o<t.length;o+=4){const t=n(4294967296*(r||s.random()));r=987654071*t(),e[o/4]=4294967296*t()|0}return t}},U={importKey:t=>new U.M(I.bytes.m(t)),_(t,e,n,s){if(n=n||1e4,0>s||0>n)throw new r("invalid params to pbkdf2");const o=1+(s>>5)<<2;let i,c,a,h,l;const u=new ArrayBuffer(o),w=new f(u);let p=0;const d=x;for(e=I.bytes.m(e),l=1;(o||1)>p;l++){for(i=c=t.encrypt(d.concat(e,[l])),a=1;n>a;a++)for(c=t.encrypt(c),h=0;h<c.length;h++)i[h]^=c[h];for(a=0;(o||1)>p&&a<i.length;a++)w.setInt32(p,i[a]),p+=4}return u.slice(0,s/8)},M:class{constructor(t){const e=this,n=e.B=R,s=[[],[]];e.D=[new n,new n];const r=e.D[0].blockSize/32;t.length>r&&(t=(new n).update(t).P());for(let e=0;r>e;e++)s[0][e]=909522486^t[e],s[1][e]=1549556828^t[e];e.D[0].update(s[0]),e.D[1].update(s[1]),e.W=new n(e.D[0])}reset(){const t=this;t.W=new t.B(t.D[0]),t.K=!1}update(t){this.K=!0,this.W.update(t)}digest(){const t=this,e=t.W.P(),n=new t.B(t.D[1]).update(e).P();return t.reset(),n}encrypt(t){if(this.K)throw new r("encrypt on already updated hmac called!");return this.update(t),this.digest(t)}}},V=typeof w!=v&&typeof w.getRandomValues==k,M="Invalid password",_="Invalid signature",B="zipjs-abort-check-password";function D(t){return V?w.getRandomValues(t):P.getRandomValues(t)}const W=16,K={name:"PBKDF2"},E=e.assign({hash:{name:"HMAC"}},K),L=e.assign({iterations:1e3,hash:{name:"SHA-1"}},K),O=["deriveBits"],T=[8,12,16],j=[16,24,32],H=10,Z=[0,0,0,0],F=typeof w!=v,N=F&&w.subtle,q=F&&typeof N!=v,G=I.bytes,J=class{constructor(t){const e=this;e.L=[[[],[],[],[],[]],[[],[],[],[],[]]],e.L[0][0][0]||e.O();const n=e.L[0][4],s=e.L[1],o=t.length;let i,c,a,h=1;if(4!==o&&6!==o&&8!==o)throw new r("invalid aes key size");for(e.v=[c=t.slice(0),a=[]],i=o;4*o+28>i;i++){let t=c[i-1];(i%o===0||8===o&&i%o===4)&&(t=n[t>>>24]<<24^n[t>>16&255]<<16^n[t>>8&255]<<8^n[255&t],i%o===0&&(t=t<<8^t>>>24^h<<24,h=h<<1^283*(h>>7))),c[i]=c[i-o]^t}for(let t=0;i;t++,i--){const e=c[3&t?i:i-4];a[t]=4>=i||4>t?e:s[0][n[e>>>24]]^s[1][n[e>>16&255]]^s[2][n[e>>8&255]]^s[3][n[255&e]]}}encrypt(t){return this.T(t,0)}decrypt(t){return this.T(t,1)}O(){const t=this.L[0],e=this.L[1],n=t[4],s=e[4],r=[],o=[];let i,c,a,h;for(let t=0;256>t;t++)o[(r[t]=t<<1^283*(t>>7))^t]=t;for(let f=i=0;!n[f];f^=c||1,i=o[i]||1){let o=i^i<<1^i<<2^i<<3^i<<4;o=o>>8^255&o^99,n[f]=o,s[o]=f,h=r[a=r[c=r[f]]];let l=16843009*h^65537*a^257*c^16843008*f,u=257*r[o]^16843008*o;for(let n=0;4>n;n++)t[n][f]=u=u<<24^u>>>8,e[n][o]=l=l<<24^l>>>8}for(let n=0;5>n;n++)t[n]=t[n].slice(0),e[n]=e[n].slice(0)}T(t,e){if(4!==t.length)throw new r("invalid aes block size");const n=this.v[e],s=n.length/4-2,o=[0,0,0,0],i=this.L[e],c=i[0],a=i[1],h=i[2],f=i[3],l=i[4];let u,w,p,d=t[0]^n[0],y=t[e?3:1]^n[1],m=t[2]^n[2],g=t[e?1:3]^n[3],S=4;for(let t=0;s>t;t++)u=c[d>>>24]^a[y>>16&255]^h[m>>8&255]^f[255&g]^n[S],w=c[y>>>24]^a[m>>16&255]^h[g>>8&255]^f[255&d]^n[S+1],p=c[m>>>24]^a[g>>16&255]^h[d>>8&255]^f[255&y]^n[S+2],g=c[g>>>24]^a[d>>16&255]^h[y>>8&255]^f[255&m]^n[S+3],S+=4,d=u,y=w,m=p;for(let t=0;4>t;t++)o[e?3&-t:t]=l[d>>>24]<<24^l[y>>16&255]<<16^l[m>>8&255]<<8^l[255&g]^n[S++],u=d,d=y,y=m,m=g,g=u;return o}},Q=class{constructor(t,e){this.j=t,this.H=e,this.Z=e}reset(){this.Z=this.H}update(t){return this.F(this.j,t,this.Z)}N(t){if(255&~(t>>24))t+=1<<24;else{let e=t>>16&255,n=t>>8&255,s=255&t;255===e?(e=0,255===n?(n=0,255===s?s=0:++s):++n):++e,t=0,t+=e<<16,t+=n<<8,t+=s}return t}q(t){0===(t[0]=this.N(t[0]))&&(t[1]=this.N(t[1]))}F(t,e,n){let s;if(!(s=e.length))return[];const r=x.h(e);for(let r=0;s>r;r+=4){this.q(n);const s=t.encrypt(n);e[r]^=s[0],e[r+1]^=s[1],e[r+2]^=s[2],e[r+3]^=s[3]}return x.l(e,r)}},X=U.M;let Y=F&&q&&typeof N.importKey==k,$=F&&q&&typeof N.deriveBits==k;class tt extends d{constructor({password:t,rawPassword:n,signed:s,encryptionStrength:i,checkPasswordOnly:c}){super({start(){e.assign(this,{ready:new l(t=>this.G=t),password:rt(t,n),signed:s,J:i-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:i,G:a,ready:h}=n;s?(await(async(t,e,n,s)=>{const o=await st(t,e,n,it(s,0,T[e])),i=it(s,T[e]);if(o[0]!=i[0]||o[1]!=i[1])throw new r(M)})(n,i,s,it(t,0,T[i]+2)),t=it(t,T[i]+2),c?e.error(new r(B)):a()):await h;const f=new o(t.length-H-(t.length-H)%W);e.enqueue(nt(n,t,f,0,H,!0))},async flush(t){const{signed:e,X:n,Y:s,pending:i,ready:c}=this;if(s&&n){await c;const a=it(i,0,i.length-H),h=it(i,i.length-H);let f=new o;if(a.length){const t=at(G,a);s.update(t);const e=n.update(t);f=ct(G,e)}if(e){const t=it(ct(G,s.digest()),0,H);for(let e=0;H>e;e++)if(t[e]!=h[e])throw new r(_)}t.enqueue(f)}}})}}class et extends d{constructor({password:t,rawPassword:n,encryptionStrength:s}){let r;super({start(){e.assign(this,{ready:new l(t=>this.G=t),password:rt(t,n),J:s-1,pending:new o})},async transform(t,e){const n=this,{password:s,J:r,G:i,ready:c}=n;let a=new o;s?(a=await(async(t,e,n)=>{const s=D(new o(T[e]));return ot(s,await st(t,e,n,s))})(n,r,s),i()):await c;const h=new o(a.length+t.length-t.length%W);h.set(a,0),e.enqueue(nt(n,t,h,a.length,0))},async flush(t){const{X:e,Y:n,pending:s,ready:i}=this;if(n&&e){await i;let c=new o;if(s.length){const t=e.update(at(G,s));n.update(t),c=ct(G,t)}r.signature=ct(G,n.digest()).slice(0,H),t.enqueue(ot(c,r.signature))}}}),r=this}}function nt(t,e,n,s,r,i){const{X:c,Y:a,pending:h}=t,f=e.length-r;let l;for(h.length&&(e=ot(h,e),n=((t,e)=>{if(e&&e>t.length){const n=t;(t=new o(e)).set(n,0)}return t})(n,f-f%W)),l=0;f-W>=l;l+=W){const t=at(G,it(e,l,l+W));i&&a.update(t);const r=c.update(t);i||a.update(r),n.set(ct(G,r),l+s)}return t.pending=it(e,l),n}async function st(n,s,r,i){n.password=null;const c=await(async(t,e,n,s,r)=>{if(!Y)return U.importKey(e);try{return await N.importKey("raw",e,n,!1,r)}catch{return Y=!1,U.importKey(e)}})(0,r,E,0,O),a=await(async(t,e,n)=>{if(!$)return U._(e,t.salt,L.iterations,n);try{return await N.deriveBits(t,e,n)}catch{return $=!1,U._(e,t.salt,L.iterations,n)}})(e.assign({salt:i},L),c,8*(2*j[s]+2)),h=new o(a),f=at(G,it(h,0,j[s])),l=at(G,it(h,j[s],2*j[s])),u=it(h,2*j[s]);return e.assign(n,{keys:{key:f,$:l,passwordVerification:u},X:new Q(new J(f),t.from(Z)),Y:new X(l)}),u}function rt(t,e){return e===b?(t=>{if(typeof u==v){const e=new o((t=unescape(encodeURIComponent(t))).length);for(let n=0;n<e.length;n++)e[n]=t.charCodeAt(n);return e}return(new u).encode(t)})(t):e}function ot(t,e){let n=t;return t.length+e.length&&(n=new o(t.length+e.length),n.set(t,0),n.set(e,t.length)),n}function it(t,e,n){return t.subarray(e,n)}function ct(t,e){return t.p(e)}function at(t,e){return t.m(e)}class ht extends d{constructor({password:t,passwordVerification:n,checkPasswordOnly:s}){super({start(){e.assign(this,{password:t,passwordVerification:n}),wt(this,t)},transform(t,e){const n=this;if(n.password){const e=lt(n,t.subarray(0,12));if(n.password=null,e.at(-1)!=n.passwordVerification)throw new r(M);t=t.subarray(12)}s?e.error(new r(B)):e.enqueue(lt(n,t))}})}}class ft extends d{constructor({password:t,passwordVerification:n}){super({start(){e.assign(this,{password:t,passwordVerification:n}),wt(this,t)},transform(t,e){const n=this;let s,r;if(n.password){n.password=null;const e=D(new o(12));e[11]=n.passwordVerification,s=new o(t.length+e.length),s.set(ut(n,e),0),r=12}else s=new o(t.length),r=0;s.set(ut(n,t),r),e.enqueue(s)}})}}function lt(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=dt(t)^e[s],pt(t,n[s]);return n}function ut(t,e){const n=new o(e.length);for(let s=0;s<e.length;s++)n[s]=dt(t)^e[s],pt(t,e[s]);return n}function wt(t,n){const s=[305419896,591751049,878082192];e.assign(t,{keys:s,tt:new C(s[0]),et:new C(s[2])});for(let e=0;e<n.length;e++)pt(t,n.charCodeAt(e))}function pt(t,e){let[n,r,o]=t.keys;t.tt.append([e]),n=~t.tt.get(),r=mt(s.imul(mt(r+yt(n)),134775813)+1),t.et.append([r>>>24]),o=~t.et.get(),t.keys=[n,r,o]}function dt(t){const e=2|t.keys[2];return yt(s.imul(e,1^e)>>>8)}function yt(t){return 255&t}function mt(t){return 4294967295&t}class gt extends d{constructor(t,{chunkSize:e,nt:n,CompressionStream:s}){super({});const{compressed:r,encrypted:o,useCompressionStream:i,zipCrypto:c,signed:a,level:h}=t,l=this;let u,w,p=super.readable;o&&!c||!a||(u=new A,p=kt(p,u)),r&&(p=vt(p,i,{level:h,chunkSize:e},s,n,s)),o&&(c?p=kt(p,new ft(t)):(w=new et(t),p=kt(p,w))),bt(l,p,()=>{let t;o&&!c&&(t=w.signature),o&&!c||!a||(t=new f(u.value.buffer).getUint32(0)),l.signature=t})}}class St extends d{constructor(t,{chunkSize:e,st:n,DecompressionStream:s}){super({});const{zipCrypto:o,encrypted:i,signed:c,signature:a,compressed:h,useCompressionStream:l,rt:u}=t;let w,p,d=super.readable;i&&(o?d=kt(d,new ht(t)):(p=new tt(t),d=kt(d,p))),h&&(d=vt(d,l,{chunkSize:e,rt:u},s,n,s)),i&&!o||!c||(w=new A,d=kt(d,w)),bt(this,d,()=>{if((!i||o)&&c){const t=new f(w.value.buffer);if(a!=t.getUint32(0,!1))throw new r(_)}})}}function bt(t,n,s){n=kt(n,new d({flush:s})),e.defineProperty(t,"readable",{get:()=>n})}function vt(t,e,n,s,r,o){const i=e&&s?s:r||o,c=n.rt?"deflate64-raw":"deflate-raw";try{t=kt(t,new i(c,n))}catch(s){if(!e)throw s;if(r)t=kt(t,new r(c,n));else{if(!o)throw s;t=kt(t,new o(c,n))}}return t}function kt(t,e){return t.pipeThrough(e)}const zt="data",Ct="close";class At extends d{constructor(t,n){super({});const s=this,{codecType:o}=t;let i;o.startsWith("deflate")?i=gt:o.startsWith("inflate")&&(i=St),s.outputSize=0;let c=0;const a=new i(t,n),h=super.readable,f=new d({transform(t,e){t&&t.length&&(c+=t.length,e.enqueue(t))},flush(){e.assign(s,{inputSize:c})}}),l=new d({transform(e,n){if(e&&e.length&&(n.enqueue(e),s.outputSize+=e.length,t.outputSize!==b&&s.outputSize>t.outputSize))throw new r("Invalid uncompressed size")},flush(){const{signature:t}=a;e.assign(s,{signature:t,inputSize:c})}});e.defineProperty(s,"readable",{get:()=>h.pipeThrough(f).pipeThrough(a).pipeThrough(l)})}}class xt extends d{constructor(t){let e;super({transform:function n(s,r){if(e){const t=new o(e.length+s.length);t.set(e),t.set(s,e.length),s=t,e=null}s.length>t?(r.enqueue(s.slice(0,t)),n(s.slice(t),r)):e=s},flush(t){e&&e.length&&t.enqueue(e)}})}}const It=new h,Rt=new h;let Pt,Ut,Vt,Mt,_t,Bt=0;async function Dt(t){try{const{options:e,config:s}=t;if(!e.useCompressionStream)try{await self.initModule(t.config)}catch{e.useCompressionStream=!0}s.CompressionStream=self.CompressionStream,s.DecompressionStream=self.DecompressionStream;const r={highWaterMark:1},o=t.readable||new y({async pull(t){const e=new l(t=>It.set(Bt,t));Wt({type:"pull",messageId:Bt}),Bt=(Bt+1)%n.MAX_SAFE_INTEGER;const{value:s,done:r}=await e;t.enqueue(s),r&&t.close()}},r),i=t.writable||new m({async write(t){let e;const s=new l(t=>e=t);Rt.set(Bt,e),Wt({type:zt,value:t,messageId:Bt}),Bt=(Bt+1)%n.MAX_SAFE_INTEGER,await s}},r),c=new At(e,s);Pt=new AbortController;const{signal:a}=Pt;await o.pipeThrough(c).pipeThrough(new xt(s.chunkSize)).pipeTo(i,{signal:a,preventClose:!0,preventAbort:!0}),await i.getWriter().close();const{signature:h,inputSize:f,outputSize:u}=c;Wt({type:Ct,result:{signature:h,inputSize:f,outputSize:u}})}catch(t){t.outputSize=0,Kt(t)}}function Wt(t){let{value:e}=t;if(e)if(e.length)try{e=new o(e),t.value=e.buffer,p(t,[t.value])}catch{p(t)}else p(t);else p(t)}function Kt(t=new r("Unknown error")){const{message:e,stack:n,code:s,name:o,outputSize:i}=t;p({error:{message:e,stack:n,code:s,name:o,outputSize:i}})}function Et(t,e,n={}){const i="number"==typeof n.level?n.level:-1,c="number"==typeof n.ot?n.ot:65536,a="number"==typeof n.it?n.it:65536;return new d({start(){let n;if(this.ct=Vt(c),this.in=Vt(a),this.it=a,this.ht=new o(c),t?(this.ft=Ut.deflate_process,this.lt=Ut.deflate_last_consumed,this.ut=Ut.deflate_end,this.wt=Ut.deflate_new(),n="gzip"===e?Ut.deflate_init_gzip(this.wt,i):"deflate-raw"===e?Ut.deflate_init_raw(this.wt,i):Ut.deflate_init(this.wt,i)):"deflate64-raw"===e?(this.ft=Ut.inflate9_process,this.lt=Ut.inflate9_last_consumed,this.ut=Ut.inflate9_end,this.wt=Ut.inflate9_new(),n=Ut.inflate9_init_raw(this.wt)):(this.ft=Ut.inflate_process,this.lt=Ut.inflate_last_consumed,this.ut=Ut.inflate_end,this.wt=Ut.inflate_new(),n="deflate-raw"===e?Ut.inflate_init_raw(this.wt):"gzip"===e?Ut.inflate_init_gzip(this.wt):Ut.inflate_init(this.wt)),0!==n)throw new r("init failed:"+n)},transform(e,n){try{const i=e,a=new o(_t.buffer),h=this.ft,f=this.lt,l=this.ct,u=this.ht;let w=0;for(;w<i.length;){const e=s.min(i.length-w,32768);this.in&&this.it>=e||(this.in&&Mt&&Mt(this.in),this.in=Vt(e),this.it=e),a.set(i.subarray(w,w+e),this.in);const o=h(this.wt,this.in,e,l,c,0),p=16777215&o;if(p&&(u.set(a.subarray(l,l+p),0),n.enqueue(u.slice(0,p))),!t){const t=o>>24&255,e=128&t?t-256:t;if(0>e)throw new r("process error:"+e)}const d=f(this.wt);if(0===d)break;w+=d}}catch(t){this.ut&&this.wt&&this.ut(this.wt),this.in&&Mt&&Mt(this.in),this.ct&&Mt&&Mt(this.ct),n.error(t)}},flush(e){try{const n=new o(_t.buffer),s=this.ft,i=this.ct,a=this.ht;for(;;){const o=s(this.wt,0,0,i,c,4),h=16777215&o,f=o>>24&255;if(!t){const t=128&f?f-256:f;if(0>t)throw new r("process error:"+t)}if(h&&(a.set(n.subarray(i,i+h),0),e.enqueue(a.slice(0,h))),1===f||0===h)break}}catch(t){e.error(t)}finally{if(this.ut&&this.wt){const t=this.ut(this.wt);0!==t&&e.error(new r("end error:"+t))}this.in&&Mt&&Mt(this.in),this.ct&&Mt&&Mt(this.ct)}}})}addEventListener("message",({data:t})=>{const{type:e,messageId:n,value:s,done:r}=t;try{if("start"==e&&Dt(t),e==zt){const t=It.get(n);It.delete(n),t({value:new o(s),done:r})}if("ack"==e){const t=Rt.get(n);Rt.delete(n),t()}e==Ct&&Pt.abort()}catch(t){Kt(t)}});class Lt{constructor(t="deflate",e){return Et(!0,t,e)}}class Ot{constructor(t="deflate",e){return Et(!1,t,e)}}let Tt=!1;self.initModule=async t=>{try{const e=await(async(t,{baseURI:e})=>{if(!Tt){let n,s;try{try{s=new URL(t,e)}catch{}const r=await fetch(s);n=await r.arrayBuffer()}catch(e){if(!t.startsWith("data:application/wasm;base64,"))throw e;n=(t=>{const e=t.split(",")[1],n=atob(e),s=n.length,r=new o(s);for(let t=0;s>t;++t)r[t]=n.charCodeAt(t);return r.buffer})(t)}(t=>{if(Ut=t,({malloc:Vt,free:Mt,memory:_t}=Ut),"function"!=typeof Vt||"function"!=typeof Mt||!_t)throw Ut=Vt=Mt=_t=null,new r("Invalid WASM module")})((await WebAssembly.instantiate(n)).instance.exports),Tt=!0}})(t.wasmURI,t);return t.nt=Lt,t.st=Ot,e}catch{}}});\n';t({workerURI:t=>{const n="text/javascript";if(t){const t=new Blob([e],{type:n});return URL.createObjectURL(t)}return "data:"+n+","+encodeURIComponent(e)}});}
214
+ function t(t){const e='(t=>{"function"==typeof define&&define.amd?define(t):t()})(function(){"use strict";const{Array:t,Object:e,Number:n,Math:s,Error:r,Uint8Array:o,Uint16Array:i,Uint32Array:a,Int32Array:c,Map:l,DataView: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)}});}
209
215
 
210
216
  /*
211
217
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
@@ -954,37 +960,6 @@
954
960
  }
955
961
  };
956
962
 
957
- /**
958
- * Random values
959
- * @namespace
960
- */
961
- const random = {
962
- /**
963
- * Generate random words with pure js, cryptographically not as strong & safe as native implementation.
964
- * @param {TypedArray} typedArray The array to fill.
965
- * @return {TypedArray} The random values.
966
- */
967
- getRandomValues(typedArray) {
968
- const words = new Uint32Array(typedArray.buffer);
969
- const r = (m_w) => {
970
- let m_z = 0x3ade68b1;
971
- const mask = 0xffffffff;
972
- return function () {
973
- m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
974
- m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
975
- const result = ((((m_z << 0x10) + m_w) & mask) / 0x100000000) + .5;
976
- return result * (Math.random() > .5 ? 1 : -1);
977
- };
978
- };
979
- for (let i = 0, rcache; i < typedArray.length; i += 4) {
980
- const _r = r((rcache || Math.random()) * 0x100000000);
981
- rcache = _r() * 0x3ade67b7;
982
- words[i / 4] = (_r() * 0x100000000) | 0;
983
- }
984
- return typedArray;
985
- }
986
- };
987
-
988
963
  /** @fileOverview CTR mode implementation.
989
964
  *
990
965
  * Special thanks to Roy Nicholson for pointing out a bug in our
@@ -1215,12 +1190,15 @@
1215
1190
  const ERR_INVALID_PASSWORD = "Invalid password";
1216
1191
  const ERR_INVALID_SIGNATURE = "Invalid signature";
1217
1192
  const ERR_ABORT_CHECK_PASSWORD = "zipjs-abort-check-password";
1193
+ const ERR_UNSUPPORTED_CRYPTO_API = "Crypto API not supported";
1218
1194
 
1219
1195
  function getRandomValues(array) {
1220
1196
  if (GET_RANDOM_VALUES_SUPPORTED) {
1221
1197
  return crypto.getRandomValues(array);
1222
1198
  } else {
1223
- return random.getRandomValues(array);
1199
+ // all supported runtimes expose crypto.getRandomValues; failing hard beats
1200
+ // silently generating predictable encryption salts
1201
+ throw new Error(ERR_UNSUPPORTED_CRYPTO_API);
1224
1202
  }
1225
1203
  }
1226
1204
 
@@ -1279,13 +1257,12 @@
1279
1257
 
1280
1258
  class AESDecryptionStream extends TransformStream {
1281
1259
 
1282
- constructor({ password, rawPassword, signed, encryptionStrength, checkPasswordOnly }) {
1260
+ constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly }) {
1283
1261
  super({
1284
1262
  start() {
1285
1263
  Object.assign(this, {
1286
1264
  ready: new Promise(resolve => this.resolveReady = resolve),
1287
1265
  password: encodePassword(password, rawPassword),
1288
- signed,
1289
1266
  strength: encryptionStrength - 1,
1290
1267
  pending: new Uint8Array()
1291
1268
  });
@@ -1314,7 +1291,6 @@
1314
1291
  },
1315
1292
  async flush(controller) {
1316
1293
  const {
1317
- signed,
1318
1294
  ctr,
1319
1295
  hmac,
1320
1296
  pending,
@@ -1331,13 +1307,15 @@
1331
1307
  const decryptedChunk = ctr.update(encryptedChunk);
1332
1308
  decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
1333
1309
  }
1334
- if (signed) {
1335
- const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1336
- for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1337
- if (signature[indexSignature] != originalSignature[indexSignature]) {
1338
- throw new Error(ERR_INVALID_SIGNATURE);
1339
- }
1340
- }
1310
+ const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
1311
+ // branch-free comparison: accumulate the differences instead of
1312
+ // short-circuiting on the first mismatching byte
1313
+ let invalidSignature = pending.length < SIGNATURE_LENGTH ? 1 : 0;
1314
+ for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
1315
+ invalidSignature |= signature[indexSignature] ^ originalSignature[indexSignature];
1316
+ }
1317
+ if (invalidSignature) {
1318
+ throw new Error(ERR_INVALID_SIGNATURE);
1341
1319
  }
1342
1320
  controller.enqueue(decryptedChunkArray);
1343
1321
  }
@@ -1409,11 +1387,11 @@
1409
1387
  hmac,
1410
1388
  pending
1411
1389
  } = aesCrypto;
1412
- const inputLength = input.length - paddingEnd;
1413
1390
  if (pending.length) {
1414
1391
  input = concat(pending, input);
1415
- output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
1416
1392
  }
1393
+ const inputLength = input.length - paddingEnd;
1394
+ output = expand(output, paddingStart + (inputLength - (inputLength % BLOCK_LENGTH)));
1417
1395
  let offset;
1418
1396
  for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
1419
1397
  const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
@@ -1561,21 +1539,24 @@
1561
1539
 
1562
1540
  class ZipCryptoDecryptionStream extends TransformStream {
1563
1541
 
1564
- constructor({ password, passwordVerification, checkPasswordOnly }) {
1542
+ constructor({ password, rawPassword, passwordVerification, checkPasswordOnly }) {
1565
1543
  super({
1566
1544
  start() {
1567
1545
  Object.assign(this, {
1568
1546
  password,
1547
+ rawPassword,
1569
1548
  passwordVerification
1570
1549
  });
1571
- createKeys(this, password);
1550
+ createKeys(this, password, rawPassword);
1572
1551
  },
1573
1552
  transform(chunk, controller) {
1574
1553
  const zipCrypto = this;
1575
- if (zipCrypto.password) {
1554
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1576
1555
  const decryptedHeader = decrypt(zipCrypto, chunk.subarray(0, HEADER_LENGTH));
1577
- zipCrypto.password = null;
1578
- if (decryptedHeader.at(-1) != zipCrypto.passwordVerification) {
1556
+ zipCrypto.password = zipCrypto.rawPassword = null;
1557
+ // verify the password with a branch-free comparison of the verification byte, mirroring
1558
+ // the constant-time AES HMAC signature check
1559
+ if ((decryptedHeader.at(-1) ^ zipCrypto.passwordVerification) != 0) {
1579
1560
  throw new Error(ERR_INVALID_PASSWORD);
1580
1561
  }
1581
1562
  chunk = chunk.subarray(HEADER_LENGTH);
@@ -1592,21 +1573,22 @@
1592
1573
 
1593
1574
  class ZipCryptoEncryptionStream extends TransformStream {
1594
1575
 
1595
- constructor({ password, passwordVerification }) {
1576
+ constructor({ password, rawPassword, passwordVerification }) {
1596
1577
  super({
1597
1578
  start() {
1598
1579
  Object.assign(this, {
1599
1580
  password,
1581
+ rawPassword,
1600
1582
  passwordVerification
1601
1583
  });
1602
- createKeys(this, password);
1584
+ createKeys(this, password, rawPassword);
1603
1585
  },
1604
1586
  transform(chunk, controller) {
1605
1587
  const zipCrypto = this;
1606
1588
  let output;
1607
1589
  let offset;
1608
- if (zipCrypto.password) {
1609
- zipCrypto.password = null;
1590
+ if (zipCrypto.password || zipCrypto.rawPassword) {
1591
+ zipCrypto.password = zipCrypto.rawPassword = null;
1610
1592
  const header = getRandomValues(new Uint8Array(HEADER_LENGTH));
1611
1593
  header[HEADER_LENGTH - 1] = zipCrypto.passwordVerification;
1612
1594
  output = new Uint8Array(chunk.length + header.length);
@@ -1641,25 +1623,31 @@
1641
1623
  return output;
1642
1624
  }
1643
1625
 
1644
- function createKeys(target, password) {
1626
+ function createKeys(target, password, rawPassword) {
1645
1627
  const keys = [0x12345678, 0x23456789, 0x34567890];
1646
1628
  Object.assign(target, {
1647
1629
  keys,
1648
1630
  crcKey0: new Crc32(keys[0]),
1649
1631
  crcKey2: new Crc32(keys[2])
1650
1632
  });
1651
- for (let index = 0; index < password.length; index++) {
1652
- updateKeys(target, password.charCodeAt(index));
1633
+ if (rawPassword) {
1634
+ for (let index = 0; index < rawPassword.length; index++) {
1635
+ updateKeys(target, rawPassword[index]);
1636
+ }
1637
+ } else {
1638
+ for (let index = 0; index < password.length; index++) {
1639
+ updateKeys(target, password.charCodeAt(index));
1640
+ }
1653
1641
  }
1654
1642
  }
1655
1643
 
1656
1644
  function updateKeys(target, byte) {
1657
- let [key0, key1, key2] = target.keys;
1645
+ let [, key1] = target.keys;
1658
1646
  target.crcKey0.append([byte]);
1659
- key0 = ~target.crcKey0.get();
1647
+ const key0 = ~target.crcKey0.get();
1660
1648
  key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
1661
1649
  target.crcKey2.append([key1 >>> 24]);
1662
- key2 = ~target.crcKey2.get();
1650
+ const key2 = ~target.crcKey2.get();
1663
1651
  target.keys = [key0, key1, key2];
1664
1652
  }
1665
1653
 
@@ -1706,6 +1694,7 @@
1706
1694
 
1707
1695
 
1708
1696
  const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
1697
+ const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
1709
1698
  const FORMAT_DEFLATE_RAW = "deflate-raw";
1710
1699
  const FORMAT_DEFLATE64_RAW = "deflate64-raw";
1711
1700
 
@@ -1762,6 +1751,7 @@
1762
1751
  }
1763
1752
  if (compressed) {
1764
1753
  readable = pipeThroughCommpressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamZlib, DecompressionStream);
1754
+ readable = mapInflateStreamError(readable);
1765
1755
  }
1766
1756
  if ((!encrypted || zipCrypto) && signed) {
1767
1757
  crc32Stream = new Crc32Stream();
@@ -1790,14 +1780,15 @@
1790
1780
  function pipeThroughCommpressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamZlib, CompressionStream) {
1791
1781
  const Stream = useCompressionStream && CompressionStreamNative ? CompressionStreamNative : CompressionStreamZlib || CompressionStream;
1792
1782
  const format = options.deflate64 ? FORMAT_DEFLATE64_RAW : FORMAT_DEFLATE_RAW;
1783
+ let codecStream;
1793
1784
  try {
1794
- readable = pipeThrough(readable, new Stream(format, options));
1785
+ codecStream = new Stream(format, options);
1795
1786
  } catch (error) {
1796
1787
  if (useCompressionStream) {
1797
1788
  if (CompressionStreamZlib) {
1798
- readable = pipeThrough(readable, new CompressionStreamZlib(format, options));
1789
+ codecStream = new CompressionStreamZlib(format, options);
1799
1790
  } else if (CompressionStream) {
1800
- readable = pipeThrough(readable, new CompressionStream(format, options));
1791
+ codecStream = new CompressionStream(format, options);
1801
1792
  } else {
1802
1793
  throw error;
1803
1794
  }
@@ -1805,13 +1796,93 @@
1805
1796
  throw error;
1806
1797
  }
1807
1798
  }
1808
- return readable;
1799
+ // The native CompressionStream/DecompressionStream and the pure-JS zlib port do not signal
1800
+ // backpressure on their writable side (their `ready` never pends), so a plain pipeThrough drains
1801
+ // the whole source into them and peak memory grows with the entry size. Awaiting each write()
1802
+ // paces the source to the codec's consumption rate, keeping streaming memory bounded. The WASM
1803
+ // codec already backpressures, so this is a no-op cost for it.
1804
+ return pipeThroughBackpressured(readable, codecStream);
1809
1805
  }
1810
1806
 
1811
1807
  function pipeThrough(readable, transformStream) {
1812
1808
  return readable.pipeThrough(transformStream);
1813
1809
  }
1814
1810
 
1811
+ // Like readable.pipeThrough(transformStream), but drives the writable side manually and awaits each
1812
+ // write() so that a codec which under-reports backpressure cannot pull the whole source into memory.
1813
+ // Errors propagate in both directions: a source error aborts the codec; a downstream cancel/error
1814
+ // (surfaced through the codec's writable rejecting) cancels the source.
1815
+ function pipeThroughBackpressured(readable, transformStream) {
1816
+ const writer = transformStream.writable.getWriter();
1817
+ const reader = readable.getReader();
1818
+ pump();
1819
+ return transformStream.readable;
1820
+
1821
+ async function pump() {
1822
+ try {
1823
+ for (; ;) {
1824
+ await writer.ready;
1825
+ const result = await reader.read();
1826
+ if (result.done) {
1827
+ await writer.close();
1828
+ break;
1829
+ }
1830
+ await writer.write(result.value);
1831
+ }
1832
+ } catch (error) {
1833
+ await abort(writer, error);
1834
+ await cancel(reader, error);
1835
+ }
1836
+ }
1837
+ }
1838
+
1839
+ async function abort(writer, error) {
1840
+ try {
1841
+ await writer.abort(error);
1842
+ } catch {
1843
+ // the writable may already be errored/closed
1844
+ }
1845
+ }
1846
+
1847
+ async function cancel(reader, error) {
1848
+ try {
1849
+ await reader.cancel(error);
1850
+ } catch {
1851
+ // the readable may already be errored/closed
1852
+ }
1853
+ }
1854
+
1855
+ // DecompressionStream implementations can fail with a message-less TypeError on malformed
1856
+ // input; give these errors an identifiable message (errors raised by the other stages of
1857
+ // the pipeline, e.g. ERR_INVALID_PASSWORD, always carry a message and pass through as-is)
1858
+ function mapInflateStreamError(readable) {
1859
+ const reader = readable.getReader();
1860
+ return new ReadableStream({
1861
+ async pull(controller) {
1862
+ let result;
1863
+ try {
1864
+ result = await reader.read();
1865
+ } catch (error) {
1866
+ if (error && error.message) {
1867
+ throw error;
1868
+ }
1869
+ const mappedError = new Error(ERR_INVALID_COMPRESSED_DATA);
1870
+ mappedError.cause = error;
1871
+ throw mappedError;
1872
+ }
1873
+ const { value, done } = result;
1874
+ if (done) {
1875
+ controller.close();
1876
+ } else {
1877
+ controller.enqueue(value);
1878
+ }
1879
+ },
1880
+ cancel(reason) {
1881
+ return reader.cancel(reason);
1882
+ }
1883
+ });
1884
+ }
1885
+
1815
1886
  /*
1816
1887
  Copyright (c) 2022 Gildas Lormeau. All rights reserved.
1817
1888
 
@@ -1841,6 +1912,7 @@
1841
1912
  */
1842
1913
 
1843
1914
 
1915
+ const DEFAULT_CHUNK_SIZE$1 = 64 * 1024;
1844
1916
  const MESSAGE_EVENT_TYPE = "message";
1845
1917
  const MESSAGE_START = "start";
1846
1918
  const MESSAGE_PULL = "pull";
@@ -1909,6 +1981,9 @@
1909
1981
 
1910
1982
  constructor(chunkSize) {
1911
1983
  let pendingChunk;
1984
+ if (!(chunkSize >= 1)) {
1985
+ chunkSize = DEFAULT_CHUNK_SIZE$1;
1986
+ }
1912
1987
  super({
1913
1988
  transform,
1914
1989
  flush(controller) {
@@ -1926,12 +2001,12 @@
1926
2001
  chunk = newChunk;
1927
2002
  pendingChunk = null;
1928
2003
  }
1929
- if (chunk.length > chunkSize) {
1930
- controller.enqueue(chunk.slice(0, chunkSize));
1931
- transform(chunk.slice(chunkSize), controller);
1932
- } else {
1933
- pendingChunk = chunk;
2004
+ let offset = 0;
2005
+ while (chunk.length - offset > chunkSize) {
2006
+ controller.enqueue(chunk.slice(offset, offset + chunkSize));
2007
+ offset += chunkSize;
1934
2008
  }
2009
+ pendingChunk = offset ? chunk.slice(offset) : chunk;
1935
2010
  }
1936
2011
  }
1937
2012
  }
@@ -1966,8 +2041,10 @@
1966
2041
 
1967
2042
 
1968
2043
  const MODULE_WORKER_OPTIONS = { type: "module" };
2044
+ const ERROR_EVENT_TYPE = "error";
2045
+ const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
1969
2046
 
1970
- let webWorkerSupported, webWorkerURI, webWorkerOptions;
2047
+ let webWorkerSupported, webWorkerSource, webWorkerURI, webWorkerOptions;
1971
2048
  let transferStreamsSupported = true;
1972
2049
  try {
1973
2050
  transferStreamsSupported = typeof structuredClone == FUNCTION_TYPE && structuredClone(new DOMException("", "AbortError")).code !== UNDEFINED_VALUE;
@@ -1986,8 +2063,9 @@
1986
2063
  const { signal } = streamOptions;
1987
2064
  Object.assign(workerData, {
1988
2065
  busy: true,
2066
+ generation: (workerData.generation || 0) + 1,
1989
2067
  readable: readable
1990
- .pipeThrough(new ChunkStream(config.chunkSize))
2068
+ .pipeThrough(new ChunkStream(getChunkSize(config)))
1991
2069
  .pipeThrough(new ProgressWatcherStream(streamOptions), { signal }),
1992
2070
  writable,
1993
2071
  options: Object.assign({}, options),
@@ -2010,15 +2088,17 @@
2010
2088
  });
2011
2089
  },
2012
2090
  onTaskFinished() {
2013
- const { resolveTerminated } = workerData;
2014
- if (resolveTerminated) {
2015
- workerData.resolveTerminated = null;
2016
- workerData.terminated = true;
2017
- workerData.worker.terminate();
2018
- resolveTerminated();
2091
+ if (workerData.busy) {
2092
+ const { resolveTerminated } = workerData;
2093
+ if (resolveTerminated) {
2094
+ workerData.resolveTerminated = null;
2095
+ workerData.terminated = true;
2096
+ workerData.worker.terminate();
2097
+ resolveTerminated();
2098
+ }
2099
+ workerData.busy = false;
2100
+ onTaskFinished(workerData);
2019
2101
  }
2020
- workerData.busy = false;
2021
- onTaskFinished(workerData);
2022
2102
  }
2023
2103
  });
2024
2104
  if (webWorkerSupported === UNDEFINED_VALUE) {
@@ -2087,6 +2167,7 @@
2087
2167
  }
2088
2168
  Object.assign(workerData, {
2089
2169
  worker,
2170
+ terminated: false,
2090
2171
  interface: {
2091
2172
  run: () => runWebWorker(workerData, { chunkSize, wasmURI, baseURI })
2092
2173
  }
@@ -2102,7 +2183,15 @@
2102
2183
  try {
2103
2184
  await initModule$1(config);
2104
2185
  } catch {
2105
- options.useCompressionStream = true;
2186
+ // The WASM module failed to load. Fall back to the native CompressionStream only if the
2187
+ // zlib codec that would otherwise run depends on that module; a self-contained codec
2188
+ // supplied through config (e.g. the pure-JS port) stays usable and is kept as requested.
2189
+ const ZlibStream = options.codecType.startsWith(CODEC_DEFLATE) ?
2190
+ config.CompressionStreamZlib :
2191
+ config.DecompressionStreamZlib;
2192
+ if (!ZlibStream || ZlibStream.requiresModule) {
2193
+ options.useCompressionStream = true;
2194
+ }
2106
2195
  }
2107
2196
  }
2108
2197
  codecStream = new CodecStream(options, config);
@@ -2141,37 +2230,85 @@
2141
2230
  result
2142
2231
  });
2143
2232
  const { readable, options } = workerData;
2144
- const { writable, closed } = watchClosedStream(workerData.writable);
2145
- const streamsTransferred = sendMessage({
2146
- type: MESSAGE_START,
2147
- options,
2148
- config,
2149
- readable,
2150
- writable
2151
- }, workerData);
2233
+ const { writable, closed, abortPipe } = watchClosedStream(workerData.writable);
2234
+ let streamsTransferred;
2235
+ try {
2236
+ streamsTransferred = sendMessage({
2237
+ type: MESSAGE_START,
2238
+ options,
2239
+ config,
2240
+ readable,
2241
+ writable
2242
+ }, workerData);
2243
+ } catch (error) {
2244
+ abortPipe();
2245
+ try {
2246
+ await closed;
2247
+ } catch {
2248
+ // ignored
2249
+ }
2250
+ workerData.onTaskFinished();
2251
+ throw error;
2252
+ }
2152
2253
  if (!streamsTransferred) {
2153
2254
  Object.assign(workerData, {
2154
2255
  reader: readable.getReader(),
2155
2256
  writer: writable.getWriter()
2156
2257
  });
2157
2258
  }
2158
- const resultValue = await result;
2159
- if (!streamsTransferred) {
2160
- await writable.getWriter().close();
2259
+ try {
2260
+ const resultValue = await result;
2261
+ await closeWritable();
2262
+ await closed;
2263
+ return resultValue;
2264
+ } catch (error) {
2265
+ await closeWritable();
2266
+ // unblock the pipe watcher if the worker died before closing its end of the stream
2267
+ abortPipe();
2268
+ try {
2269
+ await closed;
2270
+ } catch {
2271
+ // ignored
2272
+ }
2273
+ throw error;
2274
+ }
2275
+
2276
+ async function closeWritable() {
2277
+ if (!streamsTransferred && !writable.locked) {
2278
+ try {
2279
+ await writable.getWriter().close();
2280
+ } catch {
2281
+ // ignored
2282
+ }
2283
+ }
2161
2284
  }
2162
- await closed;
2163
- return resultValue;
2164
2285
  }
2165
2286
 
2166
2287
  function watchClosedStream(writableSource) {
2288
+ const abortController = new AbortController();
2167
2289
  const { writable, readable } = new TransformStream();
2168
- const closed = readable.pipeTo(writableSource, { preventClose: true });
2169
- return { writable, closed };
2290
+ const closed = readable.pipeTo(writableSource, { preventClose: true, preventAbort: true, signal: abortController.signal });
2291
+ // the pipe can fail before `closed` is awaited (e.g. the destination write fails);
2292
+ // mark the rejection as handled so it cannot kill the process in the meantime
2293
+ closed.catch(() => { });
2294
+ return { writable, closed, abortPipe: () => abortController.abort() };
2295
+ }
2296
+
2297
+ function terminateWorker$1(workerData) {
2298
+ const { worker } = workerData;
2299
+ if (worker) {
2300
+ try {
2301
+ worker.terminate();
2302
+ } catch {
2303
+ // ignored
2304
+ }
2305
+ }
2306
+ workerData.interface = null;
2170
2307
  }
2171
2308
 
2172
2309
  function getWebWorker(url, baseURI, workerData, isModuleType, useBlobURI = true) {
2173
2310
  let worker, resolvedURI, resolvedOptions;
2174
- if (webWorkerURI === UNDEFINED_VALUE) {
2311
+ if (webWorkerURI === UNDEFINED_VALUE || webWorkerSource !== url) {
2175
2312
  // deno-lint-ignore valid-typeof
2176
2313
  const isFunctionURI = typeof url == FUNCTION_TYPE;
2177
2314
  if (isFunctionURI) {
@@ -2228,16 +2365,36 @@
2228
2365
  }
2229
2366
  }
2230
2367
  }
2368
+ webWorkerSource = url;
2231
2369
  webWorkerURI = resolvedURI;
2232
2370
  webWorkerOptions = resolvedOptions;
2233
2371
  } else {
2234
2372
  worker = new Worker(webWorkerURI, webWorkerOptions);
2235
2373
  }
2236
2374
  worker.addEventListener(MESSAGE_EVENT_TYPE, event => onMessage(event, workerData));
2375
+ worker.addEventListener(ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2376
+ worker.addEventListener(MESSAGE_ERROR_EVENT_TYPE, event => onWorkerError(event, workerData));
2237
2377
  return worker;
2238
2378
  }
2239
2379
 
2240
- function sendMessage(message, { worker, writer, onTaskFinished, transferStreams }) {
2380
+ function onWorkerError(event, workerData) {
2381
+ if (event.preventDefault) {
2382
+ event.preventDefault();
2383
+ }
2384
+ const { rejectResult, writer, onTaskFinished } = workerData;
2385
+ // the worker is unusable (e.g. its script failed to load); terminate it and
2386
+ // fail the current task instead of letting it hang forever
2387
+ terminateWorker$1(workerData);
2388
+ if (rejectResult) {
2389
+ rejectResult(event.error || new Error(event.message || ERROR_EVENT_TYPE));
2390
+ if (writer) {
2391
+ writer.releaseLock();
2392
+ }
2393
+ onTaskFinished();
2394
+ }
2395
+ }
2396
+
2397
+ function sendMessage(message, { worker, writer, transferStreams }) {
2241
2398
  try {
2242
2399
  const { value, readable, writable } = message;
2243
2400
  const transferables = [];
@@ -2271,14 +2428,16 @@
2271
2428
  if (writer) {
2272
2429
  writer.releaseLock();
2273
2430
  }
2274
- onTaskFinished();
2275
2431
  throw error;
2276
2432
  }
2277
2433
  }
2278
2434
 
2279
2435
  async function onMessage({ data }, workerData) {
2280
2436
  const { type, value, messageId, result, error } = data;
2281
- const { reader, writer, resolveResult, rejectResult, onTaskFinished } = workerData;
2437
+ const { reader, writer, resolveResult, rejectResult, onTaskFinished, generation } = workerData;
2438
+ // continuations below can settle after the worker slot has been reassigned to a new
2439
+ // task (e.g. a pending pull read failing late); they must not touch the new task
2440
+ const stale = () => workerData.generation != generation;
2282
2441
  try {
2283
2442
  if (error) {
2284
2443
  const { message, stack, code, name, outputSize } = error;
@@ -2288,23 +2447,32 @@
2288
2447
  } else {
2289
2448
  if (type == MESSAGE_PULL) {
2290
2449
  const { value, done } = await reader.read();
2291
- sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2450
+ if (!stale()) {
2451
+ sendMessage({ type: MESSAGE_DATA, value, done, messageId }, workerData);
2452
+ }
2292
2453
  }
2293
2454
  if (type == MESSAGE_DATA) {
2294
2455
  await writer.ready;
2295
2456
  await writer.write(new Uint8Array(value));
2296
- sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2457
+ if (!stale()) {
2458
+ sendMessage({ type: MESSAGE_ACK_DATA, messageId }, workerData);
2459
+ }
2297
2460
  }
2298
2461
  if (type == MESSAGE_CLOSE) {
2299
2462
  close(null, result);
2300
2463
  }
2301
2464
  }
2302
2465
  } catch (error) {
2303
- sendMessage({ type: MESSAGE_CLOSE, messageId }, workerData);
2304
- close(error);
2466
+ if (!stale()) {
2467
+ terminateWorker$1(workerData);
2468
+ close(error);
2469
+ }
2305
2470
  }
2306
2471
 
2307
2472
  function close(error, result) {
2473
+ if (stale()) {
2474
+ return;
2475
+ }
2308
2476
  if (error) {
2309
2477
  rejectResult(error);
2310
2478
  } else {
@@ -2348,6 +2516,8 @@
2348
2516
 
2349
2517
  let pool = [];
2350
2518
  const pendingRequests = [];
2519
+ let starvationTimeout;
2520
+ let starvationDelay;
2351
2521
 
2352
2522
  let indexWorker = 0;
2353
2523
 
@@ -2374,14 +2544,20 @@
2374
2544
  pool.push(workerData);
2375
2545
  return new CodecWorker(workerData, stream, workerOptions, onTaskFinished);
2376
2546
  } else {
2377
- return new Promise(resolve => pendingRequests.push({ resolve, stream, workerOptions }));
2547
+ return new Promise(resolve => {
2548
+ pendingRequests.push({ resolve, stream, workerOptions });
2549
+ starvationDelay = config.workerStarvationTimeout;
2550
+ armStarvationTimeout();
2551
+ });
2378
2552
  }
2379
2553
  }
2380
2554
 
2381
2555
  function onTaskFinished(workerData) {
2556
+ clearStarvationTimeout();
2382
2557
  if (pendingRequests.length) {
2383
2558
  const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2384
2559
  resolve(new CodecWorker(workerData, stream, workerOptions, onTaskFinished));
2560
+ armStarvationTimeout();
2385
2561
  } else if (workerData.worker) {
2386
2562
  clearTerminateTimeout(workerData);
2387
2563
  terminateWorker(workerData, workerOptions);
@@ -2391,6 +2567,34 @@
2391
2567
  }
2392
2568
  }
2393
2569
 
2570
+ function armStarvationTimeout() {
2571
+ if (!starvationTimeout && pendingRequests.length && Number.isFinite(starvationDelay) && starvationDelay >= 0) {
2572
+ starvationTimeout = setTimeout(onWorkerStarvation, starvationDelay);
2573
+ }
2574
+ }
2575
+
2576
+ function clearStarvationTimeout() {
2577
+ if (starvationTimeout) {
2578
+ clearTimeout(starvationTimeout);
2579
+ starvationTimeout = null;
2580
+ }
2581
+ }
2582
+
2583
+ function onWorkerStarvation() {
2584
+ starvationTimeout = null;
2585
+ if (pendingRequests.length) {
2586
+ const [{ resolve, stream, workerOptions }] = pendingRequests.splice(0, 1);
2587
+ const inlineWorkerOptions = Object.assign({}, workerOptions, { useWebWorkers: false, workerURI: UNDEFINED_VALUE });
2588
+ resolve(new CodecWorker({}, stream, inlineWorkerOptions, onInlineTaskFinished));
2589
+ armStarvationTimeout();
2590
+ }
2591
+ }
2592
+
2593
+ function onInlineTaskFinished() {
2594
+ clearStarvationTimeout();
2595
+ armStarvationTimeout();
2596
+ }
2597
+
2394
2598
  function terminateWorker(workerData, workerOptions) {
2395
2599
  const { config } = workerOptions;
2396
2600
  const { terminateWorkerTimeout } = config;
@@ -2461,6 +2665,7 @@
2461
2665
 
2462
2666
  const CONTENT_TYPE_TEXT_PLAIN = "text/plain";
2463
2667
  const HTTP_HEADER_CONTENT_LENGTH = "Content-Length";
2668
+ const HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding";
2464
2669
  const HTTP_HEADER_CONTENT_RANGE = "Content-Range";
2465
2670
  const HTTP_HEADER_ACCEPT_RANGES = "Accept-Ranges";
2466
2671
  const HTTP_HEADER_RANGE = "Range";
@@ -2585,7 +2790,7 @@
2585
2790
 
2586
2791
  writeUint8Array(array) {
2587
2792
  const writer = this;
2588
- let indexArray = 0;
2793
+ let indexArray;
2589
2794
  let dataString = writer.pending;
2590
2795
  const delta = writer.pending.length;
2591
2796
  writer.pending = "";
@@ -2595,12 +2800,10 @@
2595
2800
  for (; indexArray < array.length; indexArray++) {
2596
2801
  writer.pending += String.fromCharCode(array[indexArray]);
2597
2802
  }
2598
- if (dataString.length) {
2599
- if (dataString.length > 2) {
2600
- writer.data += btoa(dataString);
2601
- } else {
2602
- writer.pending += dataString;
2603
- }
2803
+ if (dataString.length > 2) {
2804
+ writer.data += btoa(dataString);
2805
+ } else {
2806
+ writer.pending = dataString + writer.pending;
2604
2807
  }
2605
2808
  }
2606
2809
 
@@ -2647,6 +2850,9 @@
2647
2850
  }
2648
2851
  });
2649
2852
  writer.blob = new Response(transformStream.readable, { headers }).blob();
2853
+ // mark early rejections (e.g. aborted pipe) as handled; awaiting getData() still
2854
+ // surfaces them
2855
+ writer.blob.catch(() => { });
2650
2856
  }
2651
2857
 
2652
2858
  getData() {
@@ -2731,7 +2937,8 @@
2731
2937
  preventHeadRequest,
2732
2938
  useRangeHeader,
2733
2939
  forceRangeRequests,
2734
- combineSizeEocd
2940
+ combineSizeEocd,
2941
+ fetch
2735
2942
  } = options;
2736
2943
  options = Object.assign({}, options);
2737
2944
  delete options.preventHeadRequest;
@@ -2739,13 +2946,15 @@
2739
2946
  delete options.forceRangeRequests;
2740
2947
  delete options.combineSizeEocd;
2741
2948
  delete options.useXHR;
2949
+ delete options.fetch;
2742
2950
  Object.assign(httpReader, {
2743
2951
  url,
2744
2952
  options,
2745
2953
  preventHeadRequest,
2746
2954
  useRangeHeader,
2747
2955
  forceRangeRequests,
2748
- combineSizeEocd
2956
+ combineSizeEocd,
2957
+ fetch
2749
2958
  });
2750
2959
  }
2751
2960
 
@@ -2764,7 +2973,10 @@
2764
2973
  throw new Error(ERR_HTTP_RANGE);
2765
2974
  } else {
2766
2975
  if (combineSizeEocd) {
2767
- httpReader.eocdCache = new Uint8Array(await response.arrayBuffer());
2976
+ const eocdCache = new Uint8Array(await response.arrayBuffer());
2977
+ if (response.status == 206 && eocdCache.length == END_OF_CENTRAL_DIR_LENGTH) {
2978
+ httpReader.eocdCache = eocdCache;
2979
+ }
2768
2980
  }
2769
2981
  let contentSize;
2770
2982
  const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
@@ -2810,7 +3022,18 @@
2810
3022
  if (response.status != 206) {
2811
3023
  throw new Error(ERR_HTTP_RANGE);
2812
3024
  }
2813
- return new Uint8Array(await response.arrayBuffer());
3025
+ const contentRangeHeader = response.headers.get(HTTP_HEADER_CONTENT_RANGE);
3026
+ if (contentRangeHeader) {
3027
+ const rangeStart = Number(contentRangeHeader.trim().split(/[\s-]+/)[1]);
3028
+ if (!Number.isNaN(rangeStart) && rangeStart != index) {
3029
+ throw new Error(ERR_HTTP_RANGE);
3030
+ }
3031
+ }
3032
+ const data = new Uint8Array(await response.arrayBuffer());
3033
+ if (data.length != length) {
3034
+ throw new Error(ERR_HTTP_RANGE);
3035
+ }
3036
+ return data;
2814
3037
  }
2815
3038
  } else {
2816
3039
  const { data } = httpReader;
@@ -2847,9 +3070,9 @@
2847
3070
  async function getRequestData(httpReader, sendRequest) {
2848
3071
  const response = await sendRequest(HTTP_METHOD_GET, httpReader, getHeaders(httpReader));
2849
3072
  httpReader.data = new Uint8Array(await response.arrayBuffer());
2850
- if (!httpReader.size) {
2851
- httpReader.size = httpReader.data.length;
2852
- }
3073
+ // the downloaded content is authoritative, e.g. the Content-Length response header
3074
+ // of the HEAD request can be the encoded size when the content is compressed
3075
+ httpReader.size = httpReader.data.length;
2853
3076
  }
2854
3077
 
2855
3078
  async function getContentLength(httpReader, sendRequest, getRequestData) {
@@ -2858,7 +3081,7 @@
2858
3081
  } else {
2859
3082
  const response = await sendRequest(HTTP_METHOD_HEAD, httpReader, getHeaders(httpReader));
2860
3083
  const contentLength = response.headers.get(HTTP_HEADER_CONTENT_LENGTH);
2861
- if (contentLength) {
3084
+ if (contentLength && !response.headers.get(HTTP_HEADER_CONTENT_ENCODING)) {
2862
3085
  httpReader.size = Number(contentLength);
2863
3086
  } else {
2864
3087
  await getRequestData(httpReader, httpReader.options);
@@ -2866,8 +3089,8 @@
2866
3089
  }
2867
3090
  }
2868
3091
 
2869
- async function sendFetchRequest(method, { options, url }, headers) {
2870
- const response = await fetch(url, Object.assign({}, options, { method, headers }));
3092
+ async function sendFetchRequest(method, { fetch: fetchFunction = fetch, options, url }, headers) {
3093
+ const response = await fetchFunction(url, Object.assign({}, options, { method, headers }));
2871
3094
  if (response.status < 400) {
2872
3095
  return response;
2873
3096
  } else {
@@ -2913,7 +3136,8 @@
2913
3136
  super();
2914
3137
  Object.assign(this, {
2915
3138
  url,
2916
- reader: options.useXHR ? new XHRReader(url, options) : new FetchReader(url, options)
3139
+ // an explicit fetch implementation takes precedence over useXHR
3140
+ reader: options.useXHR && !options.fetch ? new XHRReader(url, options) : new FetchReader(url, options)
2917
3141
  });
2918
3142
  }
2919
3143
 
@@ -2938,8 +3162,7 @@
2938
3162
  class HttpRangeReader extends HttpReader {
2939
3163
 
2940
3164
  constructor(url, options = {}) {
2941
- options.useRangeHeader = true;
2942
- super(url, options);
3165
+ super(url, Object.assign({}, options, { useRangeHeader: true }));
2943
3166
  }
2944
3167
  }
2945
3168
 
@@ -3013,7 +3236,7 @@
3013
3236
  reader.lastDiskNumber = 0;
3014
3237
  reader.lastDiskOffset = 0;
3015
3238
  await Promise.all(readers.map(async (diskReader, indexDiskReader) => {
3016
- await diskReader.init();
3239
+ await initStream(diskReader);
3017
3240
  if (indexDiskReader != readers.length - 1) {
3018
3241
  reader.lastDiskOffset += diskReader.size;
3019
3242
  }
@@ -3097,14 +3320,26 @@
3097
3320
  writer.diskOffset += diskSourceWriter.size;
3098
3321
  writer.diskNumber++;
3099
3322
  diskWriter = null;
3100
- await this.write(chunk.subarray(availableSize));
3323
+ // the next disk is not opened yet but its space is available; leaving a
3324
+ // stale value here would force a new disk for every subsequent write
3325
+ writer.availableSize = writer.maxSize;
3326
+ if (chunk.length > availableSize) {
3327
+ await this.write(chunk.subarray(availableSize));
3328
+ }
3101
3329
  } else {
3102
3330
  await writeChunk(chunk);
3103
3331
  }
3104
3332
  },
3105
3333
  async close() {
3106
- await diskWriter.ready;
3107
- await closeDisk();
3334
+ if (diskWriter) {
3335
+ await diskWriter.ready;
3336
+ await closeDisk();
3337
+ }
3338
+ },
3339
+ async abort(reason) {
3340
+ if (diskWriter) {
3341
+ await diskWriter.abort(reason);
3342
+ }
3108
3343
  }
3109
3344
  });
3110
3345
  Object.defineProperty(writer, PROPERTY_NAME_WRITABLE, {
@@ -3119,7 +3354,6 @@
3119
3354
  await diskWriter.ready;
3120
3355
  await diskWriter.write(chunk);
3121
3356
  diskSourceWriter.size += chunkLength;
3122
- writer.size += chunkLength;
3123
3357
  writer.availableSize -= chunkLength;
3124
3358
  }
3125
3359
  }
@@ -3219,7 +3453,7 @@
3219
3453
 
3220
3454
  /* global TextDecoder */
3221
3455
 
3222
- const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3456
+ const CP437 = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼ !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~⌂ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ".split("");
3223
3457
  const VALID_CP437 = CP437.length == 256;
3224
3458
 
3225
3459
  function decodeCP437(stringValue) {
@@ -3267,7 +3501,8 @@
3267
3501
  if (encoding && encoding.trim().toLowerCase() == "cp437") {
3268
3502
  return decodeCP437(value);
3269
3503
  } else {
3270
- return new TextDecoder(encoding).decode(value);
3504
+ // ignoreBOM keeps a leading U+FEFF in filenames/comments instead of dropping it
3505
+ return new TextDecoder(encoding, { ignoreBOM: true }).decode(value);
3271
3506
  }
3272
3507
  }
3273
3508
 
@@ -3444,6 +3679,7 @@
3444
3679
  const OPTION_CHECK_PASSWORD_ONLY = "checkPasswordOnly";
3445
3680
  const OPTION_CHECK_OVERLAPPING_ENTRY_ONLY = "checkOverlappingEntryOnly";
3446
3681
  const OPTION_CHECK_OVERLAPPING_ENTRY = "checkOverlappingEntry";
3682
+ const OPTION_CHECK_AMBIGUITY = "checkAmbiguity";
3447
3683
  const OPTION_CHECK_SIGNATURE = "checkSignature";
3448
3684
  const OPTION_USE_WEB_WORKERS = "useWebWorkers";
3449
3685
  const OPTION_USE_COMPRESSION_STREAM = "useCompressionStream";
@@ -3501,12 +3737,16 @@
3501
3737
  const ERR_EXTRAFIELD_ZIP64_NOT_FOUND = "Zip64 extra field not found";
3502
3738
  const ERR_ENCRYPTED = "File contains encrypted entry";
3503
3739
  const ERR_UNSUPPORTED_ENCRYPTION = "Encryption method not supported";
3504
- const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
3740
+ const ERR_UNSUPPORTED_COMPRESSION$1 = "Compression method not supported";
3505
3741
  const ERR_SPLIT_ZIP_FILE = "Split zip file";
3506
3742
  const ERR_OVERLAPPING_ENTRY = "Overlapping entry found";
3743
+ const ERR_AMBIGUOUS_ARCHIVE = "Ambiguous archive";
3507
3744
  const CHARSET_UTF8 = "utf-8";
3508
3745
  const PROPERTY_NAME_UTF8_SUFFIX = "UTF8";
3509
3746
  const CHARSET_CP437 = "cp437";
3747
+ // bits of the general purpose flag that change how an entry is interpreted; the level bits (1-2) are excluded
3748
+ // because they are informative only
3749
+ const BITFLAG_AMBIGUITY_MASK = BITFLAG_ENCRYPTED | BITFLAG_DATA_DESCRIPTOR | BITFLAG_LANG_ENCODING_FLAG;
3510
3750
  const ZIP64_PROPERTIES = [
3511
3751
  [PROPERTY_NAME_UNCOMPRESSED_SIZE, MAX_32_BITS],
3512
3752
  [PROPERTY_NAME_COMPRESSED_SIZE, MAX_32_BITS],
@@ -3531,7 +3771,7 @@
3531
3771
  reader: new GenericReader(reader),
3532
3772
  options,
3533
3773
  config: getConfiguration(),
3534
- readRanges: []
3774
+ readRanges: new Map()
3535
3775
  });
3536
3776
  }
3537
3777
 
@@ -3564,21 +3804,30 @@
3564
3804
  const commentOffset = endOfDirectoryInfo.offset;
3565
3805
  const commentLength = getUint16(endOfDirectoryView, 20);
3566
3806
  const appendedDataOffset = commentOffset + END_OF_CENTRAL_DIR_LENGTH + commentLength;
3807
+ const checkAmbiguity = getOptionValue$1(zipReader, options, OPTION_CHECK_AMBIGUITY);
3808
+ if (checkAmbiguity && appendedDataOffset != reader.size) {
3809
+ throwAmbiguousArchive("appended data");
3810
+ }
3567
3811
  let lastDiskNumber = getUint16(endOfDirectoryView, 4);
3568
3812
  const expectedLastDiskNumber = reader.lastDiskNumber || 0;
3569
3813
  let diskNumber = getUint16(endOfDirectoryView, 6);
3570
- let filesLength = getUint16(endOfDirectoryView, 8);
3814
+ let filesLength = getUint16(endOfDirectoryView, 10);
3571
3815
  let prependedDataLength = 0;
3572
- let startOffset = 0;
3816
+ let startOffset;
3817
+ let zip64EndOfDirectory;
3573
3818
  if (directoryDataOffset == MAX_32_BITS || directoryDataLength == MAX_32_BITS || filesLength == MAX_16_BITS || diskNumber == MAX_16_BITS) {
3574
- const endOfDirectoryLocatorArray = await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH);
3819
+ const endOfDirectoryLocatorArray = endOfDirectoryInfo.offset >= ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH ?
3820
+ await readUint8Array(reader, endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH) :
3821
+ new Uint8Array();
3575
3822
  const endOfDirectoryLocatorView = getDataView$1(endOfDirectoryLocatorArray);
3576
- if (getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3823
+ if (endOfDirectoryLocatorArray.length == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH &&
3824
+ getUint32(endOfDirectoryLocatorView, 0) == ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE) {
3577
3825
  directoryDataOffset = getBigUint64(endOfDirectoryLocatorView, 8);
3578
3826
  let endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3579
3827
  let endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3580
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH;
3581
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3828
+ const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH - ZIP64_END_OF_CENTRAL_DIR_LENGTH - (reader.lastDiskOffset || 0);
3829
+ if ((endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) &&
3830
+ directoryDataOffset != expectedDirectoryDataOffset && expectedDirectoryDataOffset >= 0) {
3582
3831
  const originalDirectoryDataOffset = directoryDataOffset;
3583
3832
  directoryDataOffset = expectedDirectoryDataOffset;
3584
3833
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3587,24 +3836,36 @@
3587
3836
  endOfDirectoryArray = await readUint8Array(reader, directoryDataOffset, ZIP64_END_OF_CENTRAL_DIR_LENGTH, -1);
3588
3837
  endOfDirectoryView = getDataView$1(endOfDirectoryArray);
3589
3838
  }
3590
- if (getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3839
+ if (endOfDirectoryArray.length < ZIP64_END_OF_CENTRAL_DIR_LENGTH || getUint32(endOfDirectoryView, 0) != ZIP64_END_OF_CENTRAL_DIR_SIGNATURE) {
3591
3840
  throw new Error(ERR_EOCDR_LOCATOR_ZIP64_NOT_FOUND);
3592
3841
  }
3842
+ zip64EndOfDirectory = true;
3593
3843
  if (lastDiskNumber == MAX_16_BITS) {
3594
3844
  lastDiskNumber = getUint32(endOfDirectoryView, 16);
3845
+ } else if (checkAmbiguity && lastDiskNumber != getUint32(endOfDirectoryView, 16)) {
3846
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3595
3847
  }
3596
3848
  if (diskNumber == MAX_16_BITS) {
3597
3849
  diskNumber = getUint32(endOfDirectoryView, 20);
3850
+ } else if (checkAmbiguity && diskNumber != getUint32(endOfDirectoryView, 20)) {
3851
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3598
3852
  }
3599
3853
  if (filesLength == MAX_16_BITS) {
3600
3854
  filesLength = getBigUint64(endOfDirectoryView, 32);
3855
+ } else if (checkAmbiguity && filesLength != getBigUint64(endOfDirectoryView, 32)) {
3856
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3601
3857
  }
3602
3858
  if (directoryDataLength == MAX_32_BITS) {
3603
3859
  directoryDataLength = getBigUint64(endOfDirectoryView, 40);
3860
+ } else if (checkAmbiguity && directoryDataLength != getBigUint64(endOfDirectoryView, 40)) {
3861
+ throwAmbiguousArchive("mismatched zip64 end of central directory record");
3604
3862
  }
3605
- directoryDataOffset -= directoryDataLength;
3863
+ directoryDataOffset = getBigUint64(endOfDirectoryView, 48) + prependedDataLength;
3606
3864
  }
3607
3865
  }
3866
+ const declaredDirectoryDataLength = directoryDataLength;
3867
+ const centralDirectoryEndOffset = endOfDirectoryInfo.offset -
3868
+ (zip64EndOfDirectory ? ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH : 0);
3608
3869
  if (directoryDataOffset >= reader.size) {
3609
3870
  prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
3610
3871
  directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH;
@@ -3619,8 +3880,11 @@
3619
3880
  let directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3620
3881
  let directoryView = getDataView$1(directoryArray);
3621
3882
  if (directoryDataLength) {
3622
- const expectedDirectoryDataOffset = endOfDirectoryInfo.offset - directoryDataLength;
3623
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset) {
3883
+ if (directoryArray.length < 4) {
3884
+ throw new Error(ERR_BAD_FORMAT);
3885
+ }
3886
+ const expectedDirectoryDataOffset = centralDirectoryEndOffset - directoryDataLength - (reader.lastDiskOffset || 0);
3887
+ if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE && directoryDataOffset != expectedDirectoryDataOffset && diskNumber == lastDiskNumber) {
3624
3888
  const originalDirectoryDataOffset = directoryDataOffset;
3625
3889
  directoryDataOffset = expectedDirectoryDataOffset;
3626
3890
  if (directoryDataOffset > originalDirectoryDataOffset) {
@@ -3630,8 +3894,8 @@
3630
3894
  directoryView = getDataView$1(directoryArray);
3631
3895
  }
3632
3896
  }
3633
- const expectedDirectoryDataLength = endOfDirectoryInfo.offset - directoryDataOffset - (reader.lastDiskOffset || 0);
3634
- if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0) {
3897
+ const expectedDirectoryDataLength = centralDirectoryEndOffset - directoryDataOffset - (reader.lastDiskOffset || 0);
3898
+ if (directoryDataLength != expectedDirectoryDataLength && expectedDirectoryDataLength >= 0 && diskNumber == lastDiskNumber) {
3635
3899
  directoryDataLength = expectedDirectoryDataLength;
3636
3900
  directoryArray = await readUint8Array(reader, directoryDataOffset, directoryDataLength, diskNumber);
3637
3901
  directoryView = getDataView$1(directoryArray);
@@ -3639,16 +3903,19 @@
3639
3903
  if (directoryDataOffset < 0 || directoryDataOffset >= reader.size) {
3640
3904
  throw new Error(ERR_BAD_FORMAT);
3641
3905
  }
3906
+ startOffset = directoryDataOffset;
3642
3907
  const filenameEncoding = getOptionValue$1(zipReader, options, OPTION_FILENAME_ENCODING);
3643
3908
  const commentEncoding = getOptionValue$1(zipReader, options, OPTION_COMMENT_ENCODING);
3909
+ const filenames = checkAmbiguity ? new Set() : UNDEFINED_VALUE;
3910
+ let duplicateFilename;
3644
3911
  for (let indexFile = 0; indexFile < filesLength; indexFile++) {
3645
3912
  const fileEntry = new ZipEntry$1(reader, config, zipReader.options);
3646
- if (getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3913
+ if (offset + CENTRAL_FILE_HEADER_LENGTH > directoryArray.length || getUint32(directoryView, offset) != CENTRAL_FILE_HEADER_SIGNATURE) {
3647
3914
  throw new Error(ERR_CENTRAL_DIRECTORY_NOT_FOUND);
3648
3915
  }
3649
3916
  readCommonHeader(fileEntry, directoryView, offset + 6);
3650
3917
  const languageEncodingFlag = Boolean(fileEntry.bitFlag.languageEncodingFlag);
3651
- const filenameOffset = offset + 46;
3918
+ const filenameOffset = offset + CENTRAL_FILE_HEADER_LENGTH;
3652
3919
  const extraFieldOffset = filenameOffset + fileEntry.filenameLength;
3653
3920
  const commentOffset = extraFieldOffset + fileEntry.extraFieldLength;
3654
3921
  const versionMadeBy = getUint16(directoryView, offset + 4);
@@ -3669,7 +3936,7 @@
3669
3936
  directory: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_DIR_MASK),
3670
3937
  archive: Boolean(msdosAttributesRaw & FILE_ATTR_MSDOS_ARCHIVE_MASK)
3671
3938
  };
3672
- const offsetFileEntry = getUint32(directoryView, offset + 42) + prependedDataLength;
3939
+ const offsetFileEntry = getUint32(directoryView, offset + 42);
3673
3940
  const decode = getOptionValue$1(zipReader, options, OPTION_DECODE_TEXT) || decodeText;
3674
3941
  const rawFilenameEncoding = filenameUTF8 ? CHARSET_UTF8 : filenameEncoding || CHARSET_CP437;
3675
3942
  const rawCommentEncoding = commentUTF8 ? CHARSET_UTF8 : commentEncoding || CHARSET_CP437;
@@ -3682,6 +3949,7 @@
3682
3949
  comment = decodeText(rawComment, rawCommentEncoding);
3683
3950
  }
3684
3951
  Object.assign(fileEntry, {
3952
+ index: indexFile,
3685
3953
  versionMadeBy,
3686
3954
  msDosCompatible,
3687
3955
  compressedSize: 0,
@@ -3701,8 +3969,15 @@
3701
3969
  filename,
3702
3970
  comment
3703
3971
  });
3704
- startOffset = Math.max(offsetFileEntry, startOffset);
3705
3972
  readCommonFooter(fileEntry, fileEntry, directoryView, offset + 6);
3973
+ fileEntry.offset += prependedDataLength;
3974
+ startOffset = Math.min(fileEntry.offset, startOffset);
3975
+ if (checkAmbiguity) {
3976
+ if (filenames.has(fileEntry.filename)) {
3977
+ duplicateFilename = true;
3978
+ }
3979
+ filenames.add(fileEntry.filename);
3980
+ }
3706
3981
  const unixExternalUpper = (fileEntry.externalFileAttributes >> 16) & MAX_16_BITS;
3707
3982
  if (fileEntry.unixMode === UNDEFINED_VALUE && (unixExternalUpper & (FILE_ATTR_UNIX_DEFAULT_MASK | FILE_ATTR_UNIX_EXECUTABLE_MASK | FILE_ATTR_UNIX_TYPE_DIR)) != 0) {
3708
3983
  fileEntry.unixMode = unixExternalUpper;
@@ -3723,7 +3998,7 @@
3723
3998
  internalFileAttribute: fileEntry.internalFileAttributes,
3724
3999
  externalFileAttribute: fileEntry.externalFileAttributes,
3725
4000
  executable,
3726
- directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
4001
+ directory: modeIsDir || upperIsDir || (msDosCompatible && msdosAttributes.directory) || (fileEntry.filename.endsWith(DIRECTORY_SIGNATURE) && !fileEntry.uncompressedSize),
3727
4002
  zipCrypto: fileEntry.encrypted && !fileEntry.extraFieldAES
3728
4003
  });
3729
4004
  const entry = new Entry(fileEntry);
@@ -3746,6 +4021,15 @@
3746
4021
  }
3747
4022
  yield entry;
3748
4023
  }
4024
+ if (checkAmbiguity && offset != declaredDirectoryDataLength) {
4025
+ throwAmbiguousArchive("trailing central directory data");
4026
+ }
4027
+ if (duplicateFilename) {
4028
+ throwAmbiguousArchive("duplicate filename");
4029
+ }
4030
+ if (checkAmbiguity && (prependedDataLength || (filesLength && startOffset > 0))) {
4031
+ throwAmbiguousArchive("prepended data");
4032
+ }
3749
4033
  const extractPrependedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_PREPENDED_DATA);
3750
4034
  const extractAppendedData = getOptionValue$1(zipReader, options, OPTION_EXTRACT_APPENDED_DATA);
3751
4035
  if (extractPrependedData) {
@@ -3785,9 +4069,21 @@
3785
4069
  readable: (function () {
3786
4070
  const { readable, writable } = new TransformStream();
3787
4071
  if (value.getData) {
3788
- value.getData(writable);
4072
+ getData();
3789
4073
  return readable;
3790
4074
  }
4075
+
4076
+ async function getData() {
4077
+ try {
4078
+ await value.getData(writable);
4079
+ } catch (error) {
4080
+ try {
4081
+ await writable.abort(error);
4082
+ } catch {
4083
+ // ignored
4084
+ }
4085
+ }
4086
+ }
3791
4087
  })()
3792
4088
  };
3793
4089
  delete chunk.getData;
@@ -3812,6 +4108,7 @@
3812
4108
  const zipEntry = this;
3813
4109
  const {
3814
4110
  reader,
4111
+ index,
3815
4112
  offset,
3816
4113
  diskNumberStart,
3817
4114
  extraFieldAES,
@@ -3837,27 +4134,42 @@
3837
4134
  rawPassword = rawPassword && rawPassword.length && rawPassword;
3838
4135
  if (extraFieldAES) {
3839
4136
  if (extraFieldAES.originalCompressionMethod != COMPRESSION_METHOD_AES) {
3840
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4137
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3841
4138
  }
3842
4139
  }
3843
4140
  if ((compressionMethod != COMPRESSION_METHOD_STORE && compressionMethod != COMPRESSION_METHOD_DEFLATE && compressionMethod != COMPRESSION_METHOD_DEFLATE_64) && !passThrough) {
3844
- throw new Error(ERR_UNSUPPORTED_COMPRESSION);
4141
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION$1);
3845
4142
  }
3846
- if (getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
4143
+ if (dataArray.length < HEADER_SIZE || getUint32(dataView, 0) != LOCAL_FILE_HEADER_SIGNATURE) {
3847
4144
  throw new Error(ERR_LOCAL_FILE_HEADER_NOT_FOUND);
3848
4145
  }
3849
4146
  readCommonHeader(localDirectory, dataView, 4);
3850
4147
  const {
3851
4148
  extraFieldLength,
3852
- filenameLength,
3853
- lastAccessDate,
3854
- creationDate
4149
+ filenameLength
3855
4150
  } = localDirectory;
3856
- localDirectory.rawExtraField = extraFieldLength ?
3857
- await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
3858
- new Uint8Array();
4151
+ const checkAmbiguity = getOptionValue$1(zipEntry, options, OPTION_CHECK_AMBIGUITY);
4152
+ let rawLocalFilename = new Uint8Array();
4153
+ if (checkAmbiguity && (filenameLength || extraFieldLength)) {
4154
+ const trailingDataArray = await readUint8Array(reader, offset + HEADER_SIZE, filenameLength + extraFieldLength, diskNumberStart);
4155
+ rawLocalFilename = trailingDataArray.subarray(0, filenameLength);
4156
+ localDirectory.rawExtraField = trailingDataArray.subarray(filenameLength);
4157
+ } else {
4158
+ localDirectory.rawExtraField = extraFieldLength ?
4159
+ await readUint8Array(reader, offset + HEADER_SIZE + filenameLength, extraFieldLength, diskNumberStart) :
4160
+ new Uint8Array();
4161
+ }
3859
4162
  readCommonFooter(zipEntry, localDirectory, dataView, 4, true);
3860
- Object.assign(fileEntry, { lastAccessDate, creationDate });
4163
+ if (checkAmbiguity) {
4164
+ checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename);
4165
+ }
4166
+ const { lastAccessDate, creationDate } = localDirectory;
4167
+ if (lastAccessDate) {
4168
+ fileEntry.lastAccessDate = lastAccessDate;
4169
+ }
4170
+ if (creationDate) {
4171
+ fileEntry.creationDate = creationDate;
4172
+ }
3861
4173
  const encrypted = zipEntry.encrypted && localDirectory.encrypted && !passThrough;
3862
4174
  const zipCrypto = encrypted && !extraFieldAES;
3863
4175
  if (!passThrough) {
@@ -3903,7 +4215,7 @@
3903
4215
  outputSize: passThrough ? compressedSize : uncompressedSize,
3904
4216
  signature,
3905
4217
  compressed: compressionMethod != 0 && !passThrough,
3906
- encrypted: zipEntry.encrypted && !passThrough,
4218
+ encrypted,
3907
4219
  useWebWorkers: getOptionValue$1(zipEntry, options, OPTION_USE_WEB_WORKERS),
3908
4220
  useCompressionStream,
3909
4221
  transferStreams: getOptionValue$1(zipEntry, options, OPTION_TRANSFER_STREAMS),
@@ -3917,6 +4229,7 @@
3917
4229
  await detectOverlappingEntry({
3918
4230
  reader,
3919
4231
  fileEntry,
4232
+ index,
3920
4233
  offset,
3921
4234
  diskNumberStart,
3922
4235
  signature,
@@ -4019,7 +4332,7 @@
4019
4332
  directory.extraFieldUnicodeComment = extraFieldUnicodeComment;
4020
4333
  }
4021
4334
  const extraFieldAES = extraField.get(EXTRAFIELD_TYPE_AES);
4022
- if (extraFieldAES) {
4335
+ if (extraFieldAES && extraFieldAES.data.length >= 7) {
4023
4336
  readExtraFieldAES(extraFieldAES, directory, compressionMethod);
4024
4337
  directory.extraFieldAES = extraFieldAES;
4025
4338
  } else {
@@ -4056,19 +4369,23 @@
4056
4369
  directory.zip64 = true;
4057
4370
  const extraFieldView = getDataView$1(extraFieldZip64.data);
4058
4371
  const missingProperties = ZIP64_PROPERTIES.filter(([propertyName, max]) => directory[propertyName] == max);
4372
+ const requiredLength = missingProperties.reduce((length, [, max]) => length + ZIP64_EXTRACTION[max].bytes, 0);
4373
+ if (extraFieldZip64.data.length < requiredLength) {
4374
+ throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4375
+ }
4059
4376
  for (let indexMissingProperty = 0, offset = 0; indexMissingProperty < missingProperties.length; indexMissingProperty++) {
4060
4377
  const [propertyName, max] = missingProperties[indexMissingProperty];
4061
- if (directory[propertyName] == max) {
4062
- const extraction = ZIP64_EXTRACTION[max];
4063
- directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4064
- offset += extraction.bytes;
4065
- } else if (extraFieldZip64[propertyName]) {
4066
- throw new Error(ERR_EXTRAFIELD_ZIP64_NOT_FOUND);
4067
- }
4378
+ const extraction = ZIP64_EXTRACTION[max];
4379
+ directory[propertyName] = extraFieldZip64[propertyName] = extraction.getValue(extraFieldView, offset);
4380
+ offset += extraction.bytes;
4068
4381
  }
4069
4382
  }
4070
4383
 
4071
4384
  function readExtraFieldUnicode(extraFieldUnicode, propertyName, rawPropertyName, directory, fileEntry) {
4385
+ if (extraFieldUnicode.data.length < 5) {
4386
+ extraFieldUnicode.valid = false;
4387
+ return;
4388
+ }
4072
4389
  const extraFieldView = getDataView$1(extraFieldUnicode.data);
4073
4390
  const crc32 = new Crc32();
4074
4391
  crc32.append(fileEntry[rawPropertyName]);
@@ -4141,32 +4458,30 @@
4141
4458
  function readExtraFieldUnix(extraField, directory, isInfoZip) {
4142
4459
  try {
4143
4460
  const view = getDataView$1(new Uint8Array(extraField.data));
4144
- let offset = 0;
4145
- const version = getUint8(view, offset++);
4146
- const uidSize = getUint8(view, offset++);
4147
- const uidBytes = extraField.data.subarray(offset, offset + uidSize);
4148
- offset += uidSize;
4149
- const uid = unpackUnixId(uidBytes);
4150
- const gidSize = getUint8(view, offset++);
4151
- const gidBytes = extraField.data.subarray(offset, offset + gidSize);
4152
- offset += gidSize;
4153
- const gid = unpackUnixId(gidBytes);
4154
- let unixMode = UNDEFINED_VALUE;
4155
- if (!isInfoZip && offset + 2 <= extraField.data.length) {
4156
- const base = extraField.data;
4157
- const modeView = new DataView(base.buffer, base.byteOffset + offset, 2);
4158
- unixMode = modeView.getUint16(0, true);
4159
- }
4160
- Object.assign(extraField, { version, uid, gid, unixMode });
4461
+ let uid, gid;
4462
+ if (isInfoZip) {
4463
+ // Info-ZIP New Unix "ux" field (0x7875): version + variable-length uid/gid
4464
+ let offset = 0;
4465
+ const version = getUint8(view, offset++);
4466
+ const uidSize = getUint8(view, offset++);
4467
+ uid = unpackUnixId(extraField.data.subarray(offset, offset + uidSize));
4468
+ offset += uidSize;
4469
+ const gidSize = getUint8(view, offset++);
4470
+ gid = unpackUnixId(extraField.data.subarray(offset, offset + gidSize));
4471
+ Object.assign(extraField, { version, uid, gid });
4472
+ } else if (extraField.data.length >= 4) {
4473
+ // Info-ZIP Unix "Ux" field (0x7855): fixed 2-byte uid + gid (the file mode, if any, is
4474
+ // carried in the external file attributes, not here)
4475
+ uid = getUint16(view, 0);
4476
+ gid = getUint16(view, 2);
4477
+ Object.assign(extraField, { uid, gid });
4478
+ }
4161
4479
  if (uid !== UNDEFINED_VALUE) {
4162
4480
  directory.uid = uid;
4163
4481
  }
4164
4482
  if (gid !== UNDEFINED_VALUE) {
4165
4483
  directory.gid = gid;
4166
4484
  }
4167
- if (unixMode !== UNDEFINED_VALUE) {
4168
- directory.unixMode = unixMode;
4169
- }
4170
4485
  } catch {
4171
4486
  // ignored
4172
4487
  }
@@ -4180,6 +4495,9 @@
4180
4495
  }
4181
4496
 
4182
4497
  function readExtraFieldExtendedTimestamp(extraFieldExtendedTimestamp, directory, localDirectory) {
4498
+ if (!extraFieldExtendedTimestamp.data.length) {
4499
+ return;
4500
+ }
4183
4501
  const extraFieldView = getDataView$1(extraFieldExtendedTimestamp.data);
4184
4502
  const flags = getUint8(extraFieldView, 0);
4185
4503
  const timeProperties = [];
@@ -4205,7 +4523,8 @@
4205
4523
  timeProperties.forEach((propertyName, indexProperty) => {
4206
4524
  if (extraFieldExtendedTimestamp.data.length >= offset + 4) {
4207
4525
  const time = getUint32(extraFieldView, offset);
4208
- directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date(time * 1000);
4526
+ // the extended timestamp is a signed 32-bit time_t value
4527
+ directory[propertyName] = extraFieldExtendedTimestamp[propertyName] = new Date((time | 0) * 1000);
4209
4528
  const rawPropertyName = timeRawProperties[indexProperty];
4210
4529
  extraFieldExtendedTimestamp[rawPropertyName] = time;
4211
4530
  }
@@ -4216,6 +4535,7 @@
4216
4535
  async function detectOverlappingEntry({
4217
4536
  reader,
4218
4537
  fileEntry,
4538
+ index,
4219
4539
  offset,
4220
4540
  diskNumberStart,
4221
4541
  signature,
@@ -4227,10 +4547,9 @@
4227
4547
  readRanges
4228
4548
  }) {
4229
4549
  let diskOffset = 0;
4230
- if (diskNumberStart) {
4231
- for (let indexReader = 0; indexReader < diskNumberStart; indexReader++) {
4232
- const diskReader = reader.readers[indexReader];
4233
- diskOffset += diskReader.size;
4550
+ if (diskNumberStart && reader.readers) {
4551
+ for (let indexReader = 0; indexReader < Math.min(diskNumberStart, reader.readers.length); indexReader++) {
4552
+ diskOffset += reader.readers[indexReader].size;
4234
4553
  }
4235
4554
  }
4236
4555
  let dataDescriptorLength = 0;
@@ -4243,7 +4562,8 @@
4243
4562
  }
4244
4563
  if (dataDescriptorLength) {
4245
4564
  const dataDescriptorArray = await readUint8Array(reader, dataOffset + compressedSize, dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH, diskNumberStart);
4246
- const dataDescriptorSignature = getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4565
+ const dataDescriptorSignature = dataDescriptorArray.length == dataDescriptorLength + DATA_DESCRIPTOR_RECORD_SIGNATURE_LENGTH &&
4566
+ getUint32(getDataView$1(dataDescriptorArray), 0) == DATA_DESCRIPTOR_RECORD_SIGNATURE;
4247
4567
  if (dataDescriptorSignature) {
4248
4568
  const readSignature = getUint32(getDataView$1(dataDescriptorArray), 4);
4249
4569
  let readCompressedSize;
@@ -4268,14 +4588,14 @@
4268
4588
  end: diskOffset + dataOffset + compressedSize + dataDescriptorLength,
4269
4589
  fileEntry
4270
4590
  };
4271
- for (const otherRange of readRanges) {
4272
- if (otherRange.fileEntry != fileEntry && range.start >= otherRange.start && range.start < otherRange.end) {
4591
+ for (const [otherIndex, otherRange] of readRanges) {
4592
+ if (otherIndex != index && range.start < otherRange.end && otherRange.start < range.end) {
4273
4593
  const error = new Error(ERR_OVERLAPPING_ENTRY);
4274
4594
  error.overlappingEntry = otherRange.fileEntry;
4275
4595
  throw error;
4276
4596
  }
4277
4597
  }
4278
- readRanges.push(range);
4598
+ readRanges.set(index, range);
4279
4599
  }
4280
4600
 
4281
4601
  async function seekSignature(reader, signature, startOffset, minimumBytes, maximumLength) {
@@ -4300,6 +4620,35 @@
4300
4620
  }
4301
4621
  }
4302
4622
 
4623
+ function checkLocalDirectory(zipEntry, localDirectory, rawLocalFilename) {
4624
+ const { rawFilename } = zipEntry;
4625
+ if (rawLocalFilename.length != rawFilename.length ||
4626
+ rawLocalFilename.some((byteValue, indexByte) => byteValue != rawFilename[indexByte])) {
4627
+ throwAmbiguousArchive("mismatched local file header (filename)");
4628
+ }
4629
+ if ((localDirectory.rawBitFlag & BITFLAG_AMBIGUITY_MASK) != (zipEntry.rawBitFlag & BITFLAG_AMBIGUITY_MASK)) {
4630
+ throwAmbiguousArchive("mismatched local file header (general purpose bit flag)");
4631
+ }
4632
+ if (localDirectory.compressionMethod != zipEntry.compressionMethod) {
4633
+ throwAmbiguousArchive("mismatched local file header (compression method)");
4634
+ }
4635
+ // when the data descriptor flag is set, the local signature and sizes are zeroed out; all-zero values are
4636
+ // also tolerated when the flag is clear because some tools produce them (streaming writers predating bit 3)
4637
+ if (!localDirectory.bitFlag.dataDescriptor &&
4638
+ (localDirectory.signature || localDirectory.compressedSize || localDirectory.uncompressedSize) &&
4639
+ (localDirectory.signature != zipEntry.signature ||
4640
+ localDirectory.compressedSize != zipEntry.compressedSize ||
4641
+ localDirectory.uncompressedSize != zipEntry.uncompressedSize)) {
4642
+ throwAmbiguousArchive("mismatched local file header (signature or sizes)");
4643
+ }
4644
+ }
4645
+
4646
+ function throwAmbiguousArchive(reason) {
4647
+ const error = new Error(ERR_AMBIGUOUS_ARCHIVE);
4648
+ error.reason = reason;
4649
+ throw error;
4650
+ }
4651
+
4303
4652
  function getOptionValue$1(zipReader, options, name) {
4304
4653
  return options[name] === UNDEFINED_VALUE ? zipReader.options[name] : options[name];
4305
4654
  }
@@ -4338,7 +4687,7 @@
4338
4687
  }
4339
4688
 
4340
4689
  function getDataView$1(array) {
4341
- return new DataView(array.buffer);
4690
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
4342
4691
  }
4343
4692
 
4344
4693
  /*
@@ -4378,13 +4727,19 @@
4378
4727
  const ERR_INVALID_ENCRYPTION_STRENGTH = "The strength must equal 1, 2, or 3";
4379
4728
  const ERR_INVALID_EXTRAFIELD_TYPE = "Extra field type exceeds 65535";
4380
4729
  const ERR_INVALID_EXTRAFIELD_DATA = "Extra field data exceeds 64KB";
4730
+ // same message as the constant exported by zip-reader.js
4731
+ const ERR_UNSUPPORTED_COMPRESSION = "Compression method not supported";
4732
+ const MIN_UNIX_TIME = -2147483648;
4733
+ const MAX_UNIX_TIME = 2147483647;
4381
4734
  const ERR_UNSUPPORTED_FORMAT = "Zip64 is not supported (set the 'zip64' option to 'true')";
4382
4735
  const ERR_UNDEFINED_UNCOMPRESSED_SIZE = "Undefined uncompressed size";
4736
+ const ERR_UNDEFINED_READER = "Undefined reader";
4383
4737
  const ERR_ZIP_NOT_EMPTY = "Zip file not empty";
4384
4738
  const ERR_INVALID_UID = "Invalid uid (must be integer 0..2^32-1)";
4385
4739
  const ERR_INVALID_GID = "Invalid gid (must be integer 0..2^32-1)";
4386
4740
  const ERR_INVALID_UNIX_MODE = "Invalid UNIX mode (must be integer 0..65535)";
4387
4741
  const ERR_INVALID_UNIX_EXTRA_FIELD_TYPE = "Invalid unixExtraFieldType (must be 'infozip' or 'unix')";
4742
+ const ERR_INVALID_UNIX_ID_SIZE = "uid/gid must be 0..65535 for unixExtraFieldType 'unix' (use 'infozip' for larger ids)";
4388
4743
  const ERR_INVALID_MSDOS_ATTRIBUTES = "Invalid msdosAttributesRaw (must be integer 0..255)";
4389
4744
  const ERR_INVALID_MSDOS_DATA = "Invalid msdosAttributes (must be an object with boolean flags)";
4390
4745
 
@@ -4410,9 +4765,10 @@
4410
4765
  files: new Map(),
4411
4766
  filenames: new Set(),
4412
4767
  offset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? writer.size || writer.writable.size || 0 : options[OPTION_OFFSET],
4413
- pendingEntriesSize: 0,
4768
+ initialOffset: options[OPTION_OFFSET] === UNDEFINED_VALUE ? 0 : options[OPTION_OFFSET] - (writer.size || writer.writable.size || 0),
4414
4769
  pendingAddFileCalls: new Set(),
4415
- bufferedWrites: 0
4770
+ bufferedWrites: 0,
4771
+ lastFileEntry: UNDEFINED_VALUE
4416
4772
  });
4417
4773
  }
4418
4774
 
@@ -4421,17 +4777,18 @@
4421
4777
  throw new Error(ERR_ZIP_NOT_EMPTY);
4422
4778
  }
4423
4779
  reader = new GenericReader(reader);
4780
+ await initStream(reader);
4424
4781
  const zipReader = new ZipReader(reader.readable);
4425
4782
  const entries = await zipReader.getEntries();
4426
4783
  await zipReader.close();
4784
+ await initStream(this.writer);
4427
4785
  await reader.readable.pipeTo(this.writer.writable, { preventClose: true, preventAbort: true });
4428
4786
  this.writer.size = this.offset = reader.size;
4429
4787
  this.filenames = new Set(entries.map(entry => entry.filename));
4430
4788
  this.files = new Map(entries.map(entry => {
4431
4789
  const {
4432
4790
  version,
4433
- compressionMethod,
4434
- lastModDate,
4791
+ rawLastModDate,
4435
4792
  lastAccessDate,
4436
4793
  creationDate,
4437
4794
  rawFilename,
@@ -4444,6 +4801,7 @@
4444
4801
  zip64
4445
4802
  } = entry;
4446
4803
  let {
4804
+ compressionMethod,
4447
4805
  rawExtraFieldZip64,
4448
4806
  rawExtraFieldAES,
4449
4807
  rawExtraFieldExtendedTimestamp,
@@ -4456,31 +4814,39 @@
4456
4814
  rawExtraFieldAES = rawExtraFieldAES || new Uint8Array();
4457
4815
  rawExtraFieldExtendedTimestamp = rawExtraFieldExtendedTimestamp || new Uint8Array();
4458
4816
  rawExtraFieldNTFS = rawExtraFieldNTFS || new Uint8Array();
4459
- rawExtraFieldUnix = entry.rawExtraFieldUnix || new Uint8Array();
4817
+ rawExtraFieldUnix = rawExtraFieldUnix || new Uint8Array();
4460
4818
  rawExtraField = rawExtraField || new Uint8Array();
4819
+ if (entry.extraFieldAES) {
4820
+ compressionMethod = COMPRESSION_METHOD_AES;
4821
+ }
4461
4822
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
4462
- const zip64UncompressedSize = zip64 && uncompressedSize > MAX_32_BITS;
4463
- const zip64CompressedSize = zip64 && compressedSize > MAX_32_BITS;
4823
+ const zip64UncompressedSize = zip64 && uncompressedSize >= MAX_32_BITS;
4824
+ const zip64CompressedSize = zip64 && compressedSize >= MAX_32_BITS;
4825
+ const bitFlagValue = (getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod) & ~BITFLAG_LEVEL) | (level << 1);
4464
4826
  const {
4465
4827
  headerArray,
4466
4828
  headerView
4467
4829
  } = getHeaderArrayData({
4468
4830
  version,
4469
- bitFlag: getBitFlag(level, languageEncodingFlag, dataDescriptor, encrypted, compressionMethod),
4831
+ bitFlag: bitFlagValue,
4470
4832
  compressionMethod,
4471
4833
  uncompressedSize,
4472
4834
  compressedSize,
4473
- lastModDate,
4835
+ rawLastModDate,
4474
4836
  rawFilename,
4475
4837
  zip64CompressedSize,
4476
4838
  zip64UncompressedSize,
4477
4839
  extraFieldLength
4478
4840
  });
4841
+ const { signature } = entry;
4842
+ if (signature !== UNDEFINED_VALUE) {
4843
+ setUint32(headerView, HEADER_OFFSET_SIGNATURE, signature);
4844
+ }
4479
4845
  Object.assign(entry, {
4480
4846
  zip64UncompressedSize,
4481
4847
  zip64CompressedSize,
4482
- zip64Offset: zip64 && this.offset - diskOffset > MAX_32_BITS,
4483
- zip64DiskNumberStart: zip64 && diskNumber > MAX_16_BITS,
4848
+ zip64Offset: zip64 && this.offset - diskOffset >= MAX_32_BITS,
4849
+ zip64DiskNumberStart: zip64 && diskNumber >= MAX_16_BITS,
4484
4850
  rawExtraFieldZip64,
4485
4851
  rawExtraFieldAES,
4486
4852
  rawExtraFieldExtendedTimestamp,
@@ -4498,6 +4864,7 @@
4498
4864
 
4499
4865
  async add(name = "", reader, options = {}) {
4500
4866
  const zipWriter = this;
4867
+ options = Object.assign({}, options);
4501
4868
  const {
4502
4869
  pendingAddFileCalls,
4503
4870
  config
@@ -4508,17 +4875,24 @@
4508
4875
  await new Promise(resolve => pendingEntries.push(resolve));
4509
4876
  }
4510
4877
  let promiseAddFile;
4878
+ let nameAdded;
4511
4879
  try {
4512
4880
  name = name.trim();
4881
+ if (getOptionValue(zipWriter, options, PROPERTY_NAME_DIRECTORY) && !name.endsWith(DIRECTORY_SIGNATURE)) {
4882
+ name += DIRECTORY_SIGNATURE;
4883
+ }
4513
4884
  if (zipWriter.filenames.has(name)) {
4514
4885
  throw new Error(ERR_DUPLICATED_NAME);
4515
4886
  }
4516
4887
  zipWriter.filenames.add(name);
4888
+ nameAdded = true;
4517
4889
  promiseAddFile = addFile(zipWriter, name, reader, options);
4518
4890
  pendingAddFileCalls.add(promiseAddFile);
4519
4891
  return await promiseAddFile;
4520
4892
  } catch (error) {
4521
- zipWriter.filenames.delete(name);
4893
+ if (nameAdded) {
4894
+ zipWriter.filenames.delete(name);
4895
+ }
4522
4896
  throw error;
4523
4897
  } finally {
4524
4898
  pendingAddFileCalls.delete(promiseAddFile);
@@ -4551,6 +4925,9 @@
4551
4925
  const zipWriter = this;
4552
4926
  const { pendingAddFileCalls, writer } = this;
4553
4927
  const { writable } = writer;
4928
+ if (getLength(comment) > MAX_16_BITS) {
4929
+ throw new Error(ERR_INVALID_COMMENT);
4930
+ }
4554
4931
  while (pendingAddFileCalls.size) {
4555
4932
  await Promise.allSettled(Array.from(pendingAddFileCalls));
4556
4933
  }
@@ -4569,28 +4946,94 @@
4569
4946
  const { readable, writable } = new TransformStream();
4570
4947
  this.readable = readable;
4571
4948
  this.zipWriter = new ZipWriter(writable, options);
4949
+ this.pendingAddFileCalls = new Set();
4572
4950
  }
4573
4951
 
4574
4952
  transform(path) {
4953
+ const zipWriter = this.zipWriter;
4954
+ let streamController;
4575
4955
  const { readable, writable } = new TransformStream({
4576
- flush: () => { this.zipWriter.close(); }
4956
+ start(controller) {
4957
+ streamController = controller;
4958
+ },
4959
+ flush: () => void closeArchive()
4577
4960
  });
4578
- this.zipWriter.add(path, readable);
4961
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4579
4962
  return { readable: this.readable, writable };
4963
+
4964
+ async function closeArchive() {
4965
+ try {
4966
+ await zipWriter.close();
4967
+ } catch (error) {
4968
+ try {
4969
+ await zipWriter.writer.writable.abort(error);
4970
+ } catch {
4971
+ // ignored
4972
+ }
4973
+ }
4974
+ }
4580
4975
  }
4581
4976
 
4582
4977
  writable(path) {
4583
- const { readable, writable } = new TransformStream();
4584
- this.zipWriter.add(path, readable);
4978
+ let streamController;
4979
+ const { readable, writable } = new TransformStream({
4980
+ start(controller) {
4981
+ streamController = controller;
4982
+ }
4983
+ });
4984
+ watchAddFileCall(this, this.zipWriter.add(path, readable), error => streamController.error(error));
4585
4985
  return writable;
4586
4986
  }
4587
4987
 
4588
- close(comment = UNDEFINED_VALUE, options = {}) {
4988
+ async close(comment = UNDEFINED_VALUE, options = {}) {
4989
+ await Promise.all(Array.from(this.pendingAddFileCalls));
4589
4990
  return this.zipWriter.close(comment, options);
4590
4991
  }
4591
4992
  }
4592
4993
 
4994
+ function watchAddFileCall(zipWriterStream, promiseAddFile, onerror) {
4995
+ zipWriterStream.pendingAddFileCalls.add(promiseAddFile);
4996
+ promiseAddFile.catch(error => {
4997
+ try {
4998
+ onerror(error);
4999
+ } catch {
5000
+ // ignored
5001
+ }
5002
+ });
5003
+ }
5004
+
4593
5005
  async function addFile(zipWriter, name, reader, options) {
5006
+ const attributesInfo = resolveAttributes(zipWriter, name, options);
5007
+ ({ name } = attributesInfo);
5008
+ const metadataInfo = resolveMetadata(zipWriter, name, options);
5009
+ const { comment } = metadataInfo;
5010
+ const extraField = options[PROPERTY_NAME_EXTRA_FIELD];
5011
+ zipWriter.files.set(name, UNDEFINED_VALUE);
5012
+ let fileEntry;
5013
+ try {
5014
+ const sizesInfo = await resolveSizes(zipWriter, reader, metadataInfo, options);
5015
+ ({ reader } = sizesInfo);
5016
+ const { diskOffset, diskNumber } = zipWriter.writer;
5017
+ options = Object.assign({}, options, attributesInfo.resolvedOptions, metadataInfo.resolvedOptions, sizesInfo.resolvedOptions, {
5018
+ internalFileAttribute: metadataInfo.resolvedOptions.internalFileAttributes,
5019
+ externalFileAttribute: attributesInfo.resolvedOptions.externalFileAttributes,
5020
+ signature: options[PROPERTY_NAME_SIGNATURE],
5021
+ offset: zipWriter.offset - diskOffset,
5022
+ diskNumberStart: diskNumber
5023
+ });
5024
+ const headerInfo = getHeaderInfo(options);
5025
+ const dataDescriptorInfo = getDataDescriptorInfo(options);
5026
+ const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
5027
+ fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
5028
+ } catch (error) {
5029
+ zipWriter.files.delete(name);
5030
+ throw error;
5031
+ }
5032
+ Object.assign(fileEntry, { name, comment, extraField });
5033
+ return new Entry(fileEntry);
5034
+ }
5035
+
5036
+ function resolveAttributes(zipWriter, name, options) {
4594
5037
  name = name.trim();
4595
5038
  let msDosCompatible = getOptionValue(zipWriter, options, PROPERTY_NAME_MS_DOS_COMPATIBLE);
4596
5039
  let versionMadeBy = getOptionValue(zipWriter, options, PROPERTY_NAME_VERSION_MADE_BY, msDosCompatible ? 20 : 768);
@@ -4598,7 +5041,7 @@
4598
5041
  const uid = getOptionValue(zipWriter, options, PROPERTY_NAME_UID);
4599
5042
  const gid = getOptionValue(zipWriter, options, PROPERTY_NAME_GID);
4600
5043
  let unixMode = getOptionValue(zipWriter, options, PROPERTY_NAME_UNIX_MODE);
4601
- const unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
5044
+ let unixExtraFieldType = getOptionValue(zipWriter, options, OPTION_UNIX_EXTRA_FIELD_TYPE);
4602
5045
  let setuid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETUID);
4603
5046
  let setgid = getOptionValue(zipWriter, options, PROPERTY_NAME_SETGID);
4604
5047
  let sticky = getOptionValue(zipWriter, options, PROPERTY_NAME_STICKY);
@@ -4614,6 +5057,13 @@
4614
5057
  if (unixExtraFieldType !== UNDEFINED_VALUE && unixExtraFieldType !== INFOZIP_EXTRA_FIELD_TYPE && unixExtraFieldType !== UNIX_EXTRA_FIELD_TYPE) {
4615
5058
  throw new Error(ERR_INVALID_UNIX_EXTRA_FIELD_TYPE);
4616
5059
  }
5060
+ if (unixExtraFieldType === UNIX_EXTRA_FIELD_TYPE &&
5061
+ ((uid !== UNDEFINED_VALUE && uid > MAX_16_BITS) || (gid !== UNDEFINED_VALUE && gid > MAX_16_BITS))) {
5062
+ throw new Error(ERR_INVALID_UNIX_ID_SIZE);
5063
+ }
5064
+ if (unixExtraFieldType === UNDEFINED_VALUE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5065
+ unixExtraFieldType = INFOZIP_EXTRA_FIELD_TYPE;
5066
+ }
4617
5067
  let msdosAttributesRaw = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES_RAW);
4618
5068
  let msdosAttributes = getOptionValue(zipWriter, options, PROPERTY_NAME_MSDOS_ATTRIBUTES);
4619
5069
  const hasUnixMetadata = uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE || unixExtraFieldType;
@@ -4684,6 +5134,27 @@
4684
5134
  if (hasMsDosProvided) {
4685
5135
  externalFileAttributes = (externalFileAttributes & MAX_32_BITS) | (msdosAttributesRaw & MAX_8_BITS);
4686
5136
  }
5137
+ return {
5138
+ name,
5139
+ resolvedOptions: {
5140
+ versionMadeBy,
5141
+ msDosCompatible,
5142
+ externalFileAttributes,
5143
+ unixExternalUpper,
5144
+ uid,
5145
+ gid,
5146
+ unixMode,
5147
+ unixExtraFieldType,
5148
+ setuid,
5149
+ setgid,
5150
+ sticky,
5151
+ msdosAttributesRaw,
5152
+ msdosAttributes
5153
+ }
5154
+ };
5155
+ }
5156
+
5157
+ function resolveMetadata(zipWriter, name, options) {
4687
5158
  const encode = getOptionValue(zipWriter, options, OPTION_ENCODE_TEXT, encodeText);
4688
5159
  let rawFilename = encode(name);
4689
5160
  if (rawFilename === UNDEFINED_VALUE) {
@@ -4722,10 +5193,14 @@
4722
5193
  const transferStreams = getOptionValue(zipWriter, options, OPTION_TRANSFER_STREAMS, true);
4723
5194
  const bufferedWrite = getOptionValue(zipWriter, options, OPTION_BUFFERED_WRITE);
4724
5195
  const createTempStream = getOptionValue(zipWriter, options, OPTION_CREATE_TEMP_STREAM);
4725
- const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, false);
5196
+ const dataDescriptorSignature = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR_SIGNATURE, true);
4726
5197
  const signal = getOptionValue(zipWriter, options, OPTION_SIGNAL);
4727
5198
  const useUnicodeFileNames = getOptionValue(zipWriter, options, OPTION_USE_UNICODE_FILE_NAMES, true);
4728
5199
  const compressionMethod = getOptionValue(zipWriter, options, PROPERTY_NAME_COMPRESSION_METHOD);
5200
+ if (!passThrough && compressionMethod !== UNDEFINED_VALUE &&
5201
+ compressionMethod !== COMPRESSION_METHOD_STORE && compressionMethod !== COMPRESSION_METHOD_DEFLATE) {
5202
+ throw new Error(ERR_UNSUPPORTED_COMPRESSION);
5203
+ }
4729
5204
  let level = getOptionValue(zipWriter, options, OPTION_LEVEL);
4730
5205
  let useCompressionStream = getOptionValue(zipWriter, options, OPTION_USE_COMPRESSION_STREAM);
4731
5206
  let dataDescriptor = getOptionValue(zipWriter, options, OPTION_DATA_DESCRIPTOR);
@@ -4741,7 +5216,7 @@
4741
5216
  if (!useCompressionStream && (zipWriter.config.CompressionStream === UNDEFINED_VALUE && zipWriter.config.CompressionStreamZlib === UNDEFINED_VALUE)) {
4742
5217
  level = 0;
4743
5218
  }
4744
- let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5219
+ const zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
4745
5220
  if (!zipCrypto && (password !== UNDEFINED_VALUE || rawPassword !== UNDEFINED_VALUE) && !(encryptionStrength >= 1 && encryptionStrength <= 3)) {
4746
5221
  throw new Error(ERR_INVALID_ENCRYPTION_STRENGTH);
4747
5222
  }
@@ -4752,6 +5227,7 @@
4752
5227
  let offset = 0;
4753
5228
  extraField.forEach(data => extraFieldSize += 4 + getLength(data));
4754
5229
  rawExtraField = new Uint8Array(extraFieldSize);
5230
+ const rawExtraFieldView = getDataView(rawExtraField);
4755
5231
  extraField.forEach((data, type) => {
4756
5232
  if (type > MAX_16_BITS) {
4757
5233
  throw new Error(ERR_INVALID_EXTRAFIELD_TYPE);
@@ -4759,22 +5235,72 @@
4759
5235
  if (getLength(data) > MAX_16_BITS) {
4760
5236
  throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
4761
5237
  }
4762
- arraySet(rawExtraField, new Uint16Array([type]), offset);
4763
- arraySet(rawExtraField, new Uint16Array([getLength(data)]), offset + 2);
5238
+ setUint16(rawExtraFieldView, offset, type);
5239
+ setUint16(rawExtraFieldView, offset + 2, getLength(data));
4764
5240
  arraySet(rawExtraField, data, offset + 4);
4765
5241
  offset += 4 + getLength(data);
4766
5242
  });
4767
5243
  }
5244
+ return {
5245
+ comment,
5246
+ resolvedOptions: {
5247
+ rawFilename,
5248
+ rawComment,
5249
+ version,
5250
+ lastModDate,
5251
+ lastAccessDate,
5252
+ creationDate,
5253
+ internalFileAttributes,
5254
+ passThrough,
5255
+ password,
5256
+ rawPassword,
5257
+ encryptionStrength,
5258
+ zipCrypto,
5259
+ extendedTimestamp,
5260
+ keepOrder,
5261
+ useWebWorkers,
5262
+ transferStreams,
5263
+ bufferedWrite,
5264
+ createTempStream,
5265
+ dataDescriptorSignature,
5266
+ signal,
5267
+ useUnicodeFileNames,
5268
+ compressionMethod,
5269
+ level,
5270
+ useCompressionStream,
5271
+ dataDescriptor,
5272
+ zip64,
5273
+ rawExtraField
5274
+ }
5275
+ };
5276
+ }
5277
+
5278
+ async function resolveSizes(zipWriter, reader, { resolvedOptions: metadata }, options) {
5279
+ const { passThrough, zipCrypto, password, rawPassword, encryptionStrength } = metadata;
5280
+ let { dataDescriptor, zip64, level, compressionMethod } = metadata;
4768
5281
  let maximumCompressedSize = 0;
4769
- let maximumEntrySize = 0;
4770
5282
  let uncompressedSize = 0;
4771
5283
  if (passThrough) {
5284
+ // the headers of a passThrough entry describe the payload verbatim: without a
5285
+ // reader they would declare content that is not there
5286
+ if (!reader) {
5287
+ throw new Error(ERR_UNDEFINED_READER);
5288
+ }
4772
5289
  uncompressedSize = options[PROPERTY_NAME_UNCOMPRESSED_SIZE];
4773
5290
  if (uncompressedSize === UNDEFINED_VALUE) {
4774
5291
  throw new Error(ERR_UNDEFINED_UNCOMPRESSED_SIZE);
4775
5292
  }
4776
5293
  }
4777
5294
  const zip64Enabled = zip64 === true;
5295
+ const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
5296
+ // entries without a reader have no payload: write them as empty stored files instead of
5297
+ // declaring a compressed or encrypted content that does not exist
5298
+ const encryptedEntry = Boolean(reader) && (Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted));
5299
+ if (!reader) {
5300
+ level = 0;
5301
+ compressionMethod = COMPRESSION_METHOD_STORE;
5302
+ }
5303
+ const encryptionOverhead = encryptedEntry ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
4778
5304
  if (reader) {
4779
5305
  reader = new GenericReader(reader);
4780
5306
  await initStream(reader);
@@ -4787,16 +5313,15 @@
4787
5313
  }
4788
5314
  } else {
4789
5315
  options.uncompressedSize = uncompressedSize = reader.size;
4790
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5316
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4791
5317
  }
4792
5318
  } else {
4793
5319
  options.uncompressedSize = uncompressedSize;
4794
- maximumCompressedSize = getMaximumCompressedSize(uncompressedSize);
5320
+ maximumCompressedSize = getMaximumCompressedSize(uncompressedSize) + encryptionOverhead;
4795
5321
  }
4796
5322
  }
4797
- const { diskOffset, diskNumber } = zipWriter.writer;
4798
- const zip64UncompressedSize = zip64Enabled || uncompressedSize > MAX_32_BITS;
4799
- const zip64CompressedSize = zip64Enabled || maximumCompressedSize > MAX_32_BITS;
5323
+ const zip64UncompressedSize = zip64Enabled || uncompressedSize >= MAX_32_BITS;
5324
+ const zip64CompressedSize = zip64Enabled || maximumCompressedSize >= MAX_32_BITS;
4800
5325
  if (zip64UncompressedSize || zip64CompressedSize) {
4801
5326
  if (zip64 === false) {
4802
5327
  throw new Error(ERR_UNSUPPORTED_FORMAT);
@@ -4805,73 +5330,19 @@
4805
5330
  }
4806
5331
  }
4807
5332
  zip64 = zip64 || false;
4808
- const encrypted = getOptionValue(zipWriter, options, PROPERTY_NAME_ENCRYPTED);
4809
- options = Object.assign({}, options, {
4810
- rawFilename,
4811
- rawComment,
4812
- version,
4813
- versionMadeBy,
4814
- lastModDate,
4815
- lastAccessDate,
4816
- creationDate,
4817
- rawExtraField,
4818
- zip64,
4819
- zip64UncompressedSize,
4820
- zip64CompressedSize,
4821
- password,
4822
- rawPassword,
4823
- level,
4824
- useWebWorkers,
4825
- transferStreams,
4826
- encryptionStrength,
4827
- extendedTimestamp,
4828
- zipCrypto,
4829
- bufferedWrite,
4830
- createTempStream,
4831
- keepOrder,
4832
- useUnicodeFileNames,
4833
- dataDescriptor,
4834
- dataDescriptorSignature,
4835
- signal,
4836
- msDosCompatible,
4837
- internalFileAttribute: internalFileAttributes,
4838
- internalFileAttributes,
4839
- externalFileAttribute: externalFileAttributes,
4840
- externalFileAttributes,
4841
- useCompressionStream,
4842
- passThrough,
4843
- encrypted: Boolean((password && getLength(password)) || (rawPassword && getLength(rawPassword))) || (passThrough && encrypted),
4844
- signature: options[PROPERTY_NAME_SIGNATURE],
4845
- compressionMethod,
4846
- uncompressedSize,
4847
- offset: zipWriter.offset - diskOffset,
4848
- diskNumberStart: diskNumber,
4849
- uid,
4850
- gid,
4851
- setuid,
4852
- setgid,
4853
- sticky,
4854
- unixMode,
4855
- msdosAttributesRaw,
4856
- msdosAttributes,
4857
- unixExternalUpper
4858
- });
4859
- const headerInfo = getHeaderInfo(options);
4860
- const dataDescriptorInfo = getDataDescriptorInfo(options);
4861
- const metadataSize = getLength(headerInfo.localHeaderArray, dataDescriptorInfo.dataDescriptorArray);
4862
- maximumEntrySize = metadataSize + maximumCompressedSize;
4863
- if (zipWriter.options[OPTION_USDZ]) {
4864
- maximumEntrySize += maximumEntrySize + 64;
4865
- }
4866
- zipWriter.pendingEntriesSize += maximumEntrySize;
4867
- let fileEntry;
4868
- try {
4869
- fileEntry = await getFileEntry(zipWriter, name, reader, { headerInfo, dataDescriptorInfo, metadataSize }, options);
4870
- } finally {
4871
- zipWriter.pendingEntriesSize -= maximumEntrySize;
4872
- }
4873
- Object.assign(fileEntry, { name, comment, extraField });
4874
- return new Entry(fileEntry);
5333
+ return {
5334
+ reader,
5335
+ resolvedOptions: {
5336
+ dataDescriptor,
5337
+ zip64,
5338
+ zip64UncompressedSize,
5339
+ zip64CompressedSize,
5340
+ uncompressedSize,
5341
+ level,
5342
+ compressionMethod,
5343
+ encrypted: encryptedEntry
5344
+ }
5345
+ };
4875
5346
  }
4876
5347
 
4877
5348
  async function getFileEntry(zipWriter, name, reader, entryInfo, options) {
@@ -4888,37 +5359,40 @@
4888
5359
  headerInfo
4889
5360
  } = entryInfo;
4890
5361
  const usdz = zipWriter.options[OPTION_USDZ];
4891
- const previousFileEntry = Array.from(files.values()).pop();
5362
+ const previousFileEntry = zipWriter.lastFileEntry;
4892
5363
  let fileEntry = {};
4893
5364
  let bufferedWrite;
4894
5365
  let releaseLockWriter;
4895
5366
  let releaseLockCurrentFileEntry;
4896
5367
  let writingBufferedEntryData;
4897
5368
  let writingEntryData;
5369
+ let writerSizeBeforeEntry;
5370
+ let flushedBufferedSize = 0;
4898
5371
  let fileWriter;
4899
5372
  files.set(name, fileEntry);
5373
+ zipWriter.lastFileEntry = fileEntry;
4900
5374
  try {
4901
5375
  let lockPreviousFileEntry;
4902
5376
  if (keepOrder) {
4903
5377
  lockPreviousFileEntry = previousFileEntry && previousFileEntry.lock;
4904
5378
  requestLockCurrentFileEntry();
4905
5379
  }
4906
- if ((options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) && !usdz) {
5380
+ if (options.bufferedWrite || !keepOrder || zipWriter.writerLocked || zipWriter.bufferedWrites || !dataDescriptor) {
5381
+ bufferedWrite = true;
5382
+ zipWriter.bufferedWrites++;
4907
5383
  if (options.createTempStream) {
4908
5384
  fileWriter = await options.createTempStream();
4909
5385
  } else {
4910
5386
  fileWriter = new TransformStream(UNDEFINED_VALUE, UNDEFINED_VALUE, { highWaterMark: INFINITY_VALUE });
4911
5387
  }
4912
5388
  fileWriter.size = 0;
4913
- bufferedWrite = true;
4914
- zipWriter.bufferedWrites++;
4915
5389
  await initStream(writer);
4916
5390
  } else {
4917
5391
  fileWriter = writer;
4918
5392
  await requestLockWriter();
4919
5393
  }
4920
5394
  await initStream(fileWriter);
4921
- const { writable, diskOffset } = writer;
5395
+ const { diskOffset } = writer;
4922
5396
  if (zipWriter.addSplitZipSignature) {
4923
5397
  delete zipWriter.addSplitZipSignature;
4924
5398
  const signatureArray = new Uint8Array(4);
@@ -4927,21 +5401,20 @@
4927
5401
  await writeData(writer, signatureArray);
4928
5402
  zipWriter.offset += 4;
4929
5403
  }
4930
- if (usdz) {
5404
+ if (usdz && !bufferedWrite) {
4931
5405
  appendExtraFieldUSDZ(entryInfo, zipWriter.offset - diskOffset);
4932
5406
  }
4933
- const {
4934
- localHeaderView,
4935
- localHeaderArray
4936
- } = headerInfo;
5407
+ const { localHeaderArray } = headerInfo;
4937
5408
  if (!bufferedWrite) {
4938
5409
  await lockPreviousFileEntry;
4939
- await skipDiskIfNeeded(writable);
5410
+ await skipDiskIfNeeded();
4940
5411
  }
4941
- const { diskNumber } = writer;
4942
- fileEntry.diskNumberStart = diskNumber;
5412
+ const diskNumberStart = writer.diskNumber;
5413
+ const entryOffset = getSegmentOffset(zipWriter, writer);
5414
+ fileEntry.diskNumberStart = diskNumberStart;
4943
5415
  if (!bufferedWrite) {
4944
5416
  writingEntryData = true;
5417
+ writerSizeBeforeEntry = writer.size;
4945
5418
  await writeData(fileWriter, localHeaderArray);
4946
5419
  }
4947
5420
  fileEntry = await createFileEntry(reader, fileWriter, fileEntry, entryInfo, zipWriter.config, options);
@@ -4954,16 +5427,24 @@
4954
5427
  await Promise.all([fileWriter.writable.getWriter().close(), lockPreviousFileEntry]);
4955
5428
  await requestLockWriter();
4956
5429
  writingBufferedEntryData = true;
5430
+ writerSizeBeforeEntry = writer.size;
5431
+ await skipDiskIfNeeded();
4957
5432
  fileEntry.diskNumberStart = writer.diskNumber;
4958
- fileEntry.offset = zipWriter.offset - writer.diskOffset;
4959
- updateLocalHeader(fileEntry, localHeaderView, options);
4960
- await skipDiskIfNeeded(writable);
4961
- await writeData(writer, localHeaderArray);
4962
- await fileWriter.readable.pipeTo(writable, { preventClose: true, preventAbort: true, signal });
5433
+ fileEntry.offset = getSegmentOffset(zipWriter, writer);
5434
+ if (usdz) {
5435
+ // the padding depends on the entry offset, only known now that the writer is locked
5436
+ const previousMetadataSize = entryInfo.metadataSize;
5437
+ appendExtraFieldUSDZ(entryInfo, zipWriter.offset - writer.diskOffset);
5438
+ fileEntry.size += entryInfo.metadataSize - previousMetadataSize;
5439
+ }
5440
+ updateLocalHeader(fileEntry, headerInfo.localHeaderView, options);
5441
+ await writeData(writer, headerInfo.localHeaderArray);
5442
+ await flushBufferedData(fileWriter.readable, writer, signal, chunkLength => flushedBufferedSize += chunkLength);
4963
5443
  writer.size += fileWriter.size;
4964
5444
  writingBufferedEntryData = false;
4965
5445
  } else {
4966
- fileEntry.offset = zipWriter.offset - diskOffset;
5446
+ fileEntry.diskNumberStart = diskNumberStart;
5447
+ fileEntry.offset = entryOffset;
4967
5448
  }
4968
5449
  zipWriter.offset += fileEntry.size;
4969
5450
  return fileEntry;
@@ -4977,10 +5458,9 @@
4977
5458
  // ignored
4978
5459
  }
4979
5460
  }
5461
+ zipWriter.offset += writer.size - writerSizeBeforeEntry;
4980
5462
  if (bufferedWrite) {
4981
- zipWriter.offset += fileWriter.size;
4982
- } else {
4983
- zipWriter.offset = fileWriter.size;
5463
+ zipWriter.offset += flushedBufferedSize;
4984
5464
  }
4985
5465
  }
4986
5466
  files.delete(name);
@@ -5011,10 +5491,10 @@
5011
5491
  await lockWriter;
5012
5492
  }
5013
5493
 
5014
- async function skipDiskIfNeeded(writable) {
5494
+ async function skipDiskIfNeeded() {
5015
5495
  if (getLength(headerInfo.localHeaderArray) > writer.availableSize) {
5016
5496
  writer.availableSize = 0;
5017
- await writeData(writable, new Uint8Array());
5497
+ await writeData(writer, new Uint8Array());
5018
5498
  }
5019
5499
  }
5020
5500
  }
@@ -5155,6 +5635,10 @@
5155
5635
  uncompressedSize = result.inputSize;
5156
5636
  signature = result.signature;
5157
5637
  }
5638
+ if ((!zip64CompressedSize && compressedSize >= MAX_32_BITS) ||
5639
+ (!zip64UncompressedSize && uncompressedSize >= MAX_32_BITS)) {
5640
+ throw new Error(ERR_UNSUPPORTED_FORMAT);
5641
+ }
5158
5642
  } catch (error) {
5159
5643
  if (error.outputSize !== UNDEFINED_VALUE) {
5160
5644
  writer.size += error.outputSize;
@@ -5217,35 +5701,28 @@
5217
5701
  uncompressedSize
5218
5702
  } = options;
5219
5703
  let { version, compressionMethod } = options;
5220
- const compressed = !directory && (level > 0 || (level === UNDEFINED_VALUE && compressionMethod !== 0));
5704
+ const compressed = !directory && (compressionMethod === UNDEFINED_VALUE
5705
+ ? (level === UNDEFINED_VALUE || level > 0)
5706
+ : compressionMethod !== COMPRESSION_METHOD_STORE);
5221
5707
  let rawLocalExtraFieldZip64;
5222
5708
  const uncompressedFile = passThrough || !compressed;
5223
- const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5224
- if (zip64) {
5225
- let rawLocalExtraFieldZip64Length = 4;
5226
- if (zip64UncompressedSize) {
5227
- rawLocalExtraFieldZip64Length += 8;
5228
- }
5229
- if (zip64CompressedSize) {
5230
- rawLocalExtraFieldZip64Length += 8;
5231
- }
5232
- rawLocalExtraFieldZip64 = new Uint8Array(rawLocalExtraFieldZip64Length);
5233
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5234
- setUint16(rawLocalExtraFieldZip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5235
- setUint16(rawLocalExtraFieldZip64View, 2, getLength(rawLocalExtraFieldZip64) - 4);
5709
+ // entries without a data descriptor are always buffered (cf. getFileEntry), so the
5710
+ // zip64 extra field values can be patched into the local header before flushing it
5711
+ const zip64ExtraFieldComplete = zip64 && (options.bufferedWrite || !dataDescriptor || ((!zip64UncompressedSize && !zip64CompressedSize) || uncompressedFile));
5712
+ const writeLocalExtraFieldZip64 = zip64ExtraFieldComplete || (zip64 && dataDescriptor && (zip64UncompressedSize || zip64CompressedSize));
5713
+ if (zip64 && (zip64UncompressedSize || zip64CompressedSize)) {
5714
+ // APPNOTE 4.5.3: the zip64 extra field of a local header must include both the
5715
+ // uncompressed and compressed size fields
5716
+ const length = 4 + 16;
5717
+ const extraFieldZip64 = createRecordWriter(length);
5718
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
5719
+ extraFieldZip64.uint16(length - 4);
5720
+ rawLocalExtraFieldZip64 = extraFieldZip64.array;
5236
5721
  if (zip64ExtraFieldComplete) {
5237
- const rawLocalExtraFieldZip64View = getDataView(rawLocalExtraFieldZip64);
5238
- let rawLocalExtraFieldZip64Offset = 4;
5239
- if (zip64UncompressedSize) {
5240
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5241
- rawLocalExtraFieldZip64Offset += 8;
5242
- }
5243
- if (zip64CompressedSize && uncompressedFile) {
5244
- setBigUint64(rawLocalExtraFieldZip64View, rawLocalExtraFieldZip64Offset, BigInt(uncompressedSize));
5245
- rawLocalExtraFieldZip64Offset += 8;
5246
- }
5247
- if (rawLocalExtraFieldZip64Offset == 4) {
5248
- rawLocalExtraFieldZip64 = new Uint8Array();
5722
+ extraFieldZip64.uint64(uncompressedSize);
5723
+ if (uncompressedFile) {
5724
+ const encryptionOverhead = encrypted ? (zipCrypto ? 12 : 16 + encryptionStrength * 4) : 0;
5725
+ extraFieldZip64.uint64(passThrough ? 0 : uncompressedSize + encryptionOverhead);
5249
5726
  }
5250
5727
  }
5251
5728
  } else {
@@ -5253,11 +5730,11 @@
5253
5730
  }
5254
5731
  let rawExtraFieldAES;
5255
5732
  if (encrypted && !zipCrypto) {
5256
- rawExtraFieldAES = new Uint8Array(getLength(EXTRAFIELD_DATA_AES) + 2);
5257
- const extraFieldAESView = getDataView(rawExtraFieldAES);
5258
- setUint16(extraFieldAESView, 0, EXTRAFIELD_TYPE_AES);
5259
- arraySet(rawExtraFieldAES, EXTRAFIELD_DATA_AES, 2);
5260
- setUint8(extraFieldAESView, 8, encryptionStrength);
5733
+ const extraFieldAES = createRecordWriter(getLength(EXTRAFIELD_DATA_AES) + 2);
5734
+ extraFieldAES.uint16(EXTRAFIELD_TYPE_AES);
5735
+ extraFieldAES.bytes(EXTRAFIELD_DATA_AES);
5736
+ rawExtraFieldAES = extraFieldAES.array;
5737
+ rawExtraFieldAES[8] = encryptionStrength;
5261
5738
  } else {
5262
5739
  rawExtraFieldAES = new Uint8Array();
5263
5740
  }
@@ -5265,33 +5742,38 @@
5265
5742
  let rawExtraFieldExtendedTimestamp;
5266
5743
  let extraFieldExtendedTimestampFlag;
5267
5744
  if (extendedTimestamp) {
5268
- rawExtraFieldExtendedTimestamp = new Uint8Array(9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0));
5269
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldExtendedTimestamp);
5270
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5271
- setUint16(extraFieldExtendedTimestampView, 2, getLength(rawExtraFieldExtendedTimestamp) - 4);
5272
- extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5273
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5274
- let offset = 5;
5275
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastModDate.getTime() / 1000));
5276
- offset += 4;
5277
- if (lastAccessDate) {
5278
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(lastAccessDate.getTime() / 1000));
5279
- offset += 4;
5280
- }
5281
- if (creationDate) {
5282
- setUint32(extraFieldExtendedTimestampView, offset, Math.floor(creationDate.getTime() / 1000));
5745
+ const lastModTimeUnix = getTimeUnix(lastModDate);
5746
+ if (inUnixTimeRange(lastModTimeUnix)) {
5747
+ const extraFieldTimestampLength = 9 + (lastAccessDate ? 4 : 0) + (creationDate ? 4 : 0);
5748
+ const extraFieldTimestamp = createRecordWriter(extraFieldTimestampLength);
5749
+ extraFieldExtendedTimestampFlag = 0x1 + (lastAccessDate ? 0x2 : 0) + (creationDate ? 0x4 : 0);
5750
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5751
+ extraFieldTimestamp.uint16(extraFieldTimestampLength - 4);
5752
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
5753
+ extraFieldTimestamp.uint32(lastModTimeUnix);
5754
+ if (lastAccessDate) {
5755
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(lastAccessDate)));
5756
+ }
5757
+ if (creationDate) {
5758
+ extraFieldTimestamp.uint32(clampUnixTime(getTimeUnix(creationDate)));
5759
+ }
5760
+ rawExtraFieldExtendedTimestamp = extraFieldTimestamp.array;
5761
+ } else {
5762
+ // the date cannot be stored as a 32-bit time_t; the NTFS field replaces it
5763
+ rawExtraFieldExtendedTimestamp = new Uint8Array();
5283
5764
  }
5284
5765
  try {
5285
- rawExtraFieldNTFS = new Uint8Array(36);
5286
- const extraFieldNTFSView = getDataView(rawExtraFieldNTFS);
5287
5766
  const lastModTimeNTFS = getTimeNTFS(lastModDate);
5288
- setUint16(extraFieldNTFSView, 0, EXTRAFIELD_TYPE_NTFS);
5289
- setUint16(extraFieldNTFSView, 2, 32);
5290
- setUint16(extraFieldNTFSView, 8, EXTRAFIELD_TYPE_NTFS_TAG1);
5291
- setUint16(extraFieldNTFSView, 10, 24);
5292
- setBigUint64(extraFieldNTFSView, 12, lastModTimeNTFS);
5293
- setBigUint64(extraFieldNTFSView, 20, getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5294
- setBigUint64(extraFieldNTFSView, 28, getTimeNTFS(creationDate) || lastModTimeNTFS);
5767
+ const extraFieldNTFS = createRecordWriter(36);
5768
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS);
5769
+ extraFieldNTFS.uint16(32);
5770
+ extraFieldNTFS.skip(4);
5771
+ extraFieldNTFS.uint16(EXTRAFIELD_TYPE_NTFS_TAG1);
5772
+ extraFieldNTFS.uint16(24);
5773
+ extraFieldNTFS.uint64(lastModTimeNTFS);
5774
+ extraFieldNTFS.uint64(getTimeNTFS(lastAccessDate) || lastModTimeNTFS);
5775
+ extraFieldNTFS.uint64(getTimeNTFS(creationDate) || lastModTimeNTFS);
5776
+ rawExtraFieldNTFS = extraFieldNTFS.array;
5295
5777
  } catch {
5296
5778
  rawExtraFieldNTFS = new Uint8Array();
5297
5779
  }
@@ -5300,41 +5782,27 @@
5300
5782
  }
5301
5783
  let rawExtraFieldUnix;
5302
5784
  try {
5303
- const { uid, gid, unixMode, setuid, setgid, sticky, unixExtraFieldType } = options;
5304
- if (unixExtraFieldType && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE || unixMode !== UNDEFINED_VALUE)) {
5785
+ const { uid, gid, unixExtraFieldType } = options;
5786
+ if (unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5305
5787
  const uidBytes = packUnixId(uid);
5306
5788
  const gidBytes = packUnixId(gid);
5307
- let modeArray = new Uint8Array();
5308
- if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && unixMode !== UNDEFINED_VALUE) {
5309
- let modeToWrite = unixMode & MAX_16_BITS;
5310
- if (setuid) {
5311
- modeToWrite |= FILE_ATTR_UNIX_SETUID_MASK;
5312
- }
5313
- if (setgid) {
5314
- modeToWrite |= FILE_ATTR_UNIX_SETGID_MASK;
5315
- }
5316
- if (sticky) {
5317
- modeToWrite |= FILE_ATTR_UNIX_STICKY_MASK;
5318
- }
5319
- modeArray = new Uint8Array(2);
5320
- const modeDataView = new DataView(modeArray.buffer);
5321
- modeDataView.setUint16(0, modeToWrite, true);
5322
- }
5323
- const payloadLength = 3 + uidBytes.length + gidBytes.length + modeArray.length;
5324
- rawExtraFieldUnix = new Uint8Array(4 + payloadLength);
5325
- const rawExtraFieldUnixView = getDataView(rawExtraFieldUnix);
5326
- setUint16(rawExtraFieldUnixView, 0, unixExtraFieldType == INFOZIP_EXTRA_FIELD_TYPE ? EXTRAFIELD_TYPE_INFOZIP : EXTRAFIELD_TYPE_UNIX);
5327
- setUint16(rawExtraFieldUnixView, 2, payloadLength);
5328
- setUint8(rawExtraFieldUnixView, 4, 1);
5329
- setUint8(rawExtraFieldUnixView, 5, uidBytes.length);
5330
- let offset = 6;
5331
- arraySet(rawExtraFieldUnix, uidBytes, offset);
5332
- offset += uidBytes.length;
5333
- setUint8(rawExtraFieldUnixView, offset, gidBytes.length);
5334
- offset++;
5335
- arraySet(rawExtraFieldUnix, gidBytes, offset);
5336
- offset += gidBytes.length;
5337
- arraySet(rawExtraFieldUnix, modeArray, offset);
5789
+ const payloadLength = 3 + uidBytes.length + gidBytes.length;
5790
+ const extraFieldUnix = createRecordWriter(4 + payloadLength);
5791
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_INFOZIP);
5792
+ extraFieldUnix.uint16(payloadLength);
5793
+ extraFieldUnix.uint8(1);
5794
+ extraFieldUnix.uint8(uidBytes.length);
5795
+ extraFieldUnix.bytes(uidBytes);
5796
+ extraFieldUnix.uint8(gidBytes.length);
5797
+ extraFieldUnix.bytes(gidBytes);
5798
+ rawExtraFieldUnix = extraFieldUnix.array;
5799
+ } else if (unixExtraFieldType == UNIX_EXTRA_FIELD_TYPE && (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE)) {
5800
+ const extraFieldUnix = createRecordWriter(8);
5801
+ extraFieldUnix.uint16(EXTRAFIELD_TYPE_UNIX);
5802
+ extraFieldUnix.uint16(4);
5803
+ extraFieldUnix.uint16((uid === UNDEFINED_VALUE ? 0 : uid) & MAX_16_BITS);
5804
+ extraFieldUnix.uint16((gid === UNDEFINED_VALUE ? 0 : gid) & MAX_16_BITS);
5805
+ rawExtraFieldUnix = extraFieldUnix.array;
5338
5806
  } else {
5339
5807
  rawExtraFieldUnix = new Uint8Array();
5340
5808
  }
@@ -5352,8 +5820,11 @@
5352
5820
  rawExtraFieldAES[9] = compressionMethod;
5353
5821
  compressionMethod = COMPRESSION_METHOD_AES;
5354
5822
  }
5355
- const localExtraFieldZip64Length = zip64ExtraFieldComplete ? getLength(rawLocalExtraFieldZip64) : 0;
5823
+ const localExtraFieldZip64Length = writeLocalExtraFieldZip64 ? getLength(rawLocalExtraFieldZip64) : 0;
5356
5824
  const extraFieldLength = localExtraFieldZip64Length + getLength(rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5825
+ if (extraFieldLength > MAX_16_BITS) {
5826
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
5827
+ }
5357
5828
  const {
5358
5829
  headerArray,
5359
5830
  headerView,
@@ -5369,29 +5840,27 @@
5369
5840
  zip64UncompressedSize,
5370
5841
  extraFieldLength
5371
5842
  });
5372
- let localHeaderOffset = HEADER_SIZE;
5373
- const localHeaderArray = new Uint8Array(localHeaderOffset + getLength(rawFilename) + extraFieldLength);
5843
+ const localHeader = createRecordWriter(HEADER_SIZE + getLength(rawFilename) + extraFieldLength);
5844
+ const localHeaderArray = localHeader.array;
5374
5845
  const localHeaderView = getDataView(localHeaderArray);
5375
- setUint32(localHeaderView, 0, LOCAL_FILE_HEADER_SIGNATURE);
5376
- arraySet(localHeaderArray, headerArray, 4);
5377
- arraySet(localHeaderArray, rawFilename, localHeaderOffset);
5378
- localHeaderOffset += getLength(rawFilename);
5379
- if (zip64ExtraFieldComplete) {
5380
- arraySet(localHeaderArray, rawLocalExtraFieldZip64, localHeaderOffset);
5381
- }
5382
- localHeaderOffset += localExtraFieldZip64Length;
5383
- arraySet(localHeaderArray, rawExtraFieldAES, localHeaderOffset);
5384
- localHeaderOffset += getLength(rawExtraFieldAES);
5385
- arraySet(localHeaderArray, rawExtraFieldExtendedTimestamp, localHeaderOffset);
5386
- localHeaderOffset += getLength(rawExtraFieldExtendedTimestamp);
5387
- arraySet(localHeaderArray, rawExtraFieldNTFS, localHeaderOffset);
5388
- localHeaderOffset += getLength(rawExtraFieldNTFS);
5389
- arraySet(localHeaderArray, rawExtraFieldUnix, localHeaderOffset);
5390
- localHeaderOffset += getLength(rawExtraFieldUnix);
5391
- arraySet(localHeaderArray, rawExtraField, localHeaderOffset);
5846
+ localHeader.uint32(LOCAL_FILE_HEADER_SIGNATURE);
5847
+ localHeader.bytes(headerArray);
5848
+ localHeader.bytes(rawFilename);
5849
+ if (writeLocalExtraFieldZip64) {
5850
+ localHeader.bytes(rawLocalExtraFieldZip64);
5851
+ }
5852
+ localHeader.bytes(rawExtraFieldAES);
5853
+ localHeader.bytes(rawExtraFieldExtendedTimestamp);
5854
+ localHeader.bytes(rawExtraFieldNTFS);
5855
+ localHeader.bytes(rawExtraFieldUnix);
5856
+ localHeader.bytes(rawExtraField);
5392
5857
  if (dataDescriptor) {
5393
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, 0);
5394
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, 0);
5858
+ if (!zip64CompressedSize) {
5859
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5860
+ }
5861
+ if (!zip64UncompressedSize) {
5862
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, 0);
5863
+ }
5395
5864
  }
5396
5865
  return {
5397
5866
  localHeaderArray,
@@ -5418,7 +5887,7 @@
5418
5887
  function appendExtraFieldUSDZ(entryInfo, zipWriterOffset) {
5419
5888
  const { headerInfo } = entryInfo;
5420
5889
  let { localHeaderArray, extraFieldLength } = headerInfo;
5421
- let localHeaderArrayView = getDataView(localHeaderArray);
5890
+ let localHeaderArrayView;
5422
5891
  let extraBytesLength = 64 - ((zipWriterOffset + getLength(localHeaderArray)) % 64);
5423
5892
  if (extraBytesLength < 4) {
5424
5893
  extraBytesLength += 64;
@@ -5426,13 +5895,14 @@
5426
5895
  const rawExtraFieldUSDZ = new Uint8Array(extraBytesLength);
5427
5896
  const extraFieldUSDZView = getDataView(rawExtraFieldUSDZ);
5428
5897
  setUint16(extraFieldUSDZView, 0, EXTRAFIELD_TYPE_USDZ);
5429
- setUint16(extraFieldUSDZView, 2, extraBytesLength - 2);
5898
+ setUint16(extraFieldUSDZView, 2, extraBytesLength - 4);
5430
5899
  const previousLocalHeaderArray = localHeaderArray;
5431
5900
  headerInfo.localHeaderArray = localHeaderArray = new Uint8Array(getLength(previousLocalHeaderArray) + extraBytesLength);
5432
5901
  arraySet(localHeaderArray, previousLocalHeaderArray);
5433
5902
  arraySet(localHeaderArray, rawExtraFieldUSDZ, getLength(previousLocalHeaderArray));
5434
5903
  localHeaderArrayView = getDataView(localHeaderArray);
5435
5904
  setUint16(localHeaderArrayView, 28, extraFieldLength + extraBytesLength);
5905
+ headerInfo.localHeaderView = localHeaderArrayView;
5436
5906
  entryInfo.metadataSize += extraBytesLength;
5437
5907
  }
5438
5908
 
@@ -5555,37 +6025,32 @@
5555
6025
  }, localHeaderView, { dataDescriptor }) {
5556
6026
  if (!dataDescriptor) {
5557
6027
  if (!encrypted) {
5558
- setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + 4, signature);
6028
+ setUint32(localHeaderView, HEADER_OFFSET_SIGNATURE + LOCAL_HEADER_COMMON_OFFSET, signature);
5559
6029
  }
5560
6030
  if (!zip64CompressedSize) {
5561
- setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + 4, compressedSize);
6031
+ setUint32(localHeaderView, HEADER_OFFSET_COMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, compressedSize);
5562
6032
  }
5563
6033
  if (!zip64UncompressedSize) {
5564
- setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + 4, uncompressedSize);
6034
+ setUint32(localHeaderView, HEADER_OFFSET_UNCOMPRESSED_SIZE + LOCAL_HEADER_COMMON_OFFSET, uncompressedSize);
5565
6035
  }
5566
6036
  }
5567
6037
  if (zip64 && localExtraFieldZip64Length) {
5568
- let localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
5569
- if (zip64UncompressedSize) {
5570
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
5571
- localHeaderOffset += 8;
5572
- }
5573
- if (zip64CompressedSize) {
5574
- setBigUint64(localHeaderView, localHeaderOffset, BigInt(compressedSize));
5575
- localHeaderOffset += 8;
5576
- }
6038
+ // the local zip64 extra field always contains both size slots
6039
+ const localHeaderOffset = HEADER_SIZE + getLength(rawFilename) + 4;
6040
+ setBigUint64(localHeaderView, localHeaderOffset, BigInt(uncompressedSize));
6041
+ setBigUint64(localHeaderView, localHeaderOffset + 8, BigInt(compressedSize));
5577
6042
  }
5578
6043
  }
5579
6044
 
5580
6045
 
5581
6046
  async function closeFile(zipWriter, comment, options) {
5582
- const { files, writer } = zipWriter;
5583
- const { diskOffset } = writer;
5584
- let { diskNumber } = writer;
5585
- let offset = 0;
6047
+ const directoryDataLength = createDirectoryRecords(zipWriter.files);
6048
+ const { cdStartDiskNumber, cdStartDiskOffset } = await writeDirectoryRecords(zipWriter, directoryDataLength, options);
6049
+ await writeEndOfDirectoryRecord(zipWriter, comment, options, { cdStartDiskNumber, cdStartDiskOffset, directoryDataLength });
6050
+ }
6051
+
6052
+ function createDirectoryRecords(files) {
5586
6053
  let directoryDataLength = 0;
5587
- let directoryOffset = zipWriter.offset - diskOffset;
5588
- let filesLength = files.size;
5589
6054
  for (const [, fileEntry] of files) {
5590
6055
  const {
5591
6056
  rawFilename,
@@ -5602,24 +6067,27 @@
5602
6067
  uncompressedSize,
5603
6068
  compressedSize
5604
6069
  } = fileEntry;
5605
- const zip64Offset = fileEntry.offset > MAX_32_BITS;
5606
- const zip64DiskNumberStart = fileEntry.diskNumberStart > MAX_16_BITS;
6070
+ const zip64Offset = fileEntry.offset >= MAX_32_BITS;
6071
+ const zip64DiskNumberStart = fileEntry.diskNumberStart >= MAX_16_BITS;
5607
6072
  let rawExtraFieldZip64;
5608
6073
  if (zip64Offset || zip64DiskNumberStart || zip64UncompressedSize || zip64CompressedSize) {
5609
- let length = 4;
5610
- if (zip64UncompressedSize) length += 8;
5611
- if (zip64CompressedSize) length += 8;
5612
- if (zip64Offset) length += 8;
5613
- if (zip64DiskNumberStart) length += 4;
5614
- rawExtraFieldZip64 = new Uint8Array(length);
5615
- const zip64View = getDataView(rawExtraFieldZip64);
5616
- setUint16(zip64View, 0, EXTRAFIELD_TYPE_ZIP64);
5617
- setUint16(zip64View, 2, length - 4);
5618
- let zip64FieldOffset = 4;
5619
- if (zip64UncompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(uncompressedSize)); zip64FieldOffset += 8; }
5620
- if (zip64CompressedSize) { setBigUint64(zip64View, zip64FieldOffset, BigInt(compressedSize)); zip64FieldOffset += 8; }
5621
- if (zip64Offset) { setBigUint64(zip64View, zip64FieldOffset, BigInt(fileEntry.offset)); zip64FieldOffset += 8; }
5622
- if (zip64DiskNumberStart) { setUint32(zip64View, zip64FieldOffset, fileEntry.diskNumberStart); }
6074
+ const length = 4 + (zip64UncompressedSize ? 8 : 0) + (zip64CompressedSize ? 8 : 0) + (zip64Offset ? 8 : 0) + (zip64DiskNumberStart ? 4 : 0);
6075
+ const extraFieldZip64 = createRecordWriter(length);
6076
+ extraFieldZip64.uint16(EXTRAFIELD_TYPE_ZIP64);
6077
+ extraFieldZip64.uint16(length - 4);
6078
+ if (zip64UncompressedSize) {
6079
+ extraFieldZip64.uint64(uncompressedSize);
6080
+ }
6081
+ if (zip64CompressedSize) {
6082
+ extraFieldZip64.uint64(compressedSize);
6083
+ }
6084
+ if (zip64Offset) {
6085
+ extraFieldZip64.uint64(fileEntry.offset);
6086
+ }
6087
+ if (zip64DiskNumberStart) {
6088
+ extraFieldZip64.uint32(fileEntry.diskNumberStart);
6089
+ }
6090
+ rawExtraFieldZip64 = extraFieldZip64.array;
5623
6091
  } else {
5624
6092
  rawExtraFieldZip64 = new Uint8Array();
5625
6093
  }
@@ -5627,32 +6095,41 @@
5627
6095
  fileEntry.zip64Offset = zip64Offset;
5628
6096
  fileEntry.zip64DiskNumberStart = zip64DiskNumberStart;
5629
6097
  let rawExtraFieldTimestamp;
5630
- if (extendedTimestamp) {
5631
- rawExtraFieldTimestamp = new Uint8Array(9);
5632
- const extraFieldExtendedTimestampView = getDataView(rawExtraFieldTimestamp);
5633
- setUint16(extraFieldExtendedTimestampView, 0, EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
5634
- setUint16(extraFieldExtendedTimestampView, 2, 5);
5635
- setUint8(extraFieldExtendedTimestampView, 4, extraFieldExtendedTimestampFlag);
5636
- setUint32(extraFieldExtendedTimestampView, 5, Math.floor(lastModDate.getTime() / 1000));
6098
+ const lastModTimeUnix = getTimeUnix(lastModDate);
6099
+ if (extendedTimestamp && inUnixTimeRange(lastModTimeUnix)) {
6100
+ const extraFieldTimestamp = createRecordWriter(9);
6101
+ extraFieldTimestamp.uint16(EXTRAFIELD_TYPE_EXTENDED_TIMESTAMP);
6102
+ extraFieldTimestamp.uint16(5);
6103
+ extraFieldTimestamp.uint8(extraFieldExtendedTimestampFlag);
6104
+ extraFieldTimestamp.uint32(lastModTimeUnix);
6105
+ rawExtraFieldTimestamp = extraFieldTimestamp.array;
5637
6106
  } else {
5638
6107
  rawExtraFieldTimestamp = new Uint8Array();
5639
6108
  }
5640
6109
  fileEntry.rawExtraFieldExtendedTimestamp = rawExtraFieldTimestamp;
5641
- directoryDataLength += 46 +
5642
- getLength(
5643
- rawFilename,
5644
- rawComment,
5645
- rawExtraFieldZip64,
5646
- rawExtraFieldAES,
5647
- rawExtraFieldNTFS,
5648
- rawExtraFieldUnix,
5649
- rawExtraFieldTimestamp,
5650
- rawExtraField);
6110
+ const extraFieldLength = getLength(
6111
+ rawExtraFieldZip64,
6112
+ rawExtraFieldAES,
6113
+ rawExtraFieldNTFS,
6114
+ rawExtraFieldUnix,
6115
+ rawExtraFieldTimestamp,
6116
+ rawExtraField);
6117
+ if (extraFieldLength > MAX_16_BITS) {
6118
+ throw new Error(ERR_INVALID_EXTRAFIELD_DATA);
6119
+ }
6120
+ directoryDataLength += CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
5651
6121
  }
6122
+ return directoryDataLength;
6123
+ }
6124
+
6125
+ async function writeDirectoryRecords(zipWriter, directoryDataLength, options) {
6126
+ const { files, writer } = zipWriter;
5652
6127
  const directoryArray = new Uint8Array(directoryDataLength);
5653
- const directoryView = getDataView(directoryArray);
5654
6128
  await initStream(writer);
6129
+ let offset = 0;
5655
6130
  let directoryDiskOffset = 0;
6131
+ let cdStartDiskNumber = writer.diskNumber;
6132
+ let cdStartDiskOffset = writer.diskOffset;
5656
6133
  for (const [indexFileEntry, fileEntry] of Array.from(files.values()).entries()) {
5657
6134
  const {
5658
6135
  offset: fileEntryOffset,
@@ -5678,52 +6155,46 @@
5678
6155
  compressedSize
5679
6156
  } = fileEntry;
5680
6157
  const extraFieldLength = getLength(rawExtraFieldZip64, rawExtraFieldAES, rawExtraFieldExtendedTimestamp, rawExtraFieldNTFS, rawExtraFieldUnix, rawExtraField);
5681
- setUint32(directoryView, offset, CENTRAL_FILE_HEADER_SIGNATURE);
5682
- setUint16(directoryView, offset + 4, versionMadeBy);
6158
+ const directoryRecordLength = CENTRAL_FILE_HEADER_LENGTH + getLength(rawFilename, rawComment) + extraFieldLength;
6159
+ if (offset + directoryRecordLength - directoryDiskOffset > writer.availableSize) {
6160
+ await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
6161
+ directoryDiskOffset = offset;
6162
+ writer.availableSize = 0;
6163
+ await writeData(writer, new Uint8Array());
6164
+ }
6165
+ if (indexFileEntry == 0) {
6166
+ cdStartDiskNumber = writer.diskNumber;
6167
+ cdStartDiskOffset = writer.diskOffset;
6168
+ }
5683
6169
  if (!zip64UncompressedSize) {
5684
6170
  setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, uncompressedSize);
5685
6171
  }
5686
6172
  if (!zip64CompressedSize) {
5687
6173
  setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, compressedSize);
5688
6174
  }
5689
- arraySet(directoryArray, headerArray, offset + 6);
5690
- let directoryOffset = offset + HEADER_SIZE;
5691
- setUint16(directoryView, directoryOffset, extraFieldLength);
5692
- directoryOffset += 2;
5693
- setUint16(directoryView, directoryOffset, getLength(rawComment));
5694
- directoryOffset += 2;
5695
- setUint16(directoryView, directoryOffset, zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
5696
- directoryOffset += 2;
5697
- setUint16(directoryView, directoryOffset, internalFileAttributes);
5698
- directoryOffset += 2;
5699
- if (externalFileAttributes) {
5700
- setUint32(directoryView, directoryOffset, externalFileAttributes);
5701
- }
5702
- directoryOffset += 4;
5703
- setUint32(directoryView, directoryOffset, zip64Offset ? MAX_32_BITS : fileEntryOffset);
5704
- directoryOffset += 4;
5705
- arraySet(directoryArray, rawFilename, directoryOffset);
5706
- directoryOffset += getLength(rawFilename);
5707
- arraySet(directoryArray, rawExtraFieldZip64, directoryOffset);
5708
- directoryOffset += getLength(rawExtraFieldZip64);
5709
- arraySet(directoryArray, rawExtraFieldAES, directoryOffset);
5710
- directoryOffset += getLength(rawExtraFieldAES);
5711
- arraySet(directoryArray, rawExtraFieldExtendedTimestamp, directoryOffset);
5712
- directoryOffset += getLength(rawExtraFieldExtendedTimestamp);
5713
- arraySet(directoryArray, rawExtraFieldNTFS, directoryOffset);
5714
- directoryOffset += getLength(rawExtraFieldNTFS);
5715
- arraySet(directoryArray, rawExtraFieldUnix, directoryOffset);
5716
- directoryOffset += getLength(rawExtraFieldUnix);
5717
- arraySet(directoryArray, rawExtraField, directoryOffset);
5718
- directoryOffset += getLength(rawExtraField);
5719
- arraySet(directoryArray, rawComment, directoryOffset);
5720
- directoryOffset += getLength(rawComment);
5721
- if (offset - directoryDiskOffset > writer.availableSize) {
5722
- writer.availableSize = 0;
5723
- await writeData(writer, directoryArray.slice(directoryDiskOffset, offset));
5724
- directoryDiskOffset = offset;
5725
- }
5726
- offset = directoryOffset;
6175
+ if ((zip64Offset || zip64DiskNumberStart) && fileEntry.version < VERSION_ZIP64) {
6176
+ setUint16(headerView, HEADER_OFFSET_VERSION, VERSION_ZIP64);
6177
+ }
6178
+ const directoryRecord = createRecordWriter(directoryRecordLength);
6179
+ directoryRecord.uint32(CENTRAL_FILE_HEADER_SIGNATURE);
6180
+ directoryRecord.uint16(versionMadeBy);
6181
+ directoryRecord.bytes(headerArray.subarray(0, HEADER_SIZE - 4 - 2));
6182
+ directoryRecord.uint16(extraFieldLength);
6183
+ directoryRecord.uint16(getLength(rawComment));
6184
+ directoryRecord.uint16(zip64DiskNumberStart ? MAX_16_BITS : diskNumberStart);
6185
+ directoryRecord.uint16(internalFileAttributes);
6186
+ directoryRecord.uint32(externalFileAttributes);
6187
+ directoryRecord.uint32(zip64Offset ? MAX_32_BITS : fileEntryOffset);
6188
+ directoryRecord.bytes(rawFilename);
6189
+ directoryRecord.bytes(rawExtraFieldZip64);
6190
+ directoryRecord.bytes(rawExtraFieldAES);
6191
+ directoryRecord.bytes(rawExtraFieldExtendedTimestamp);
6192
+ directoryRecord.bytes(rawExtraFieldNTFS);
6193
+ directoryRecord.bytes(rawExtraFieldUnix);
6194
+ directoryRecord.bytes(rawExtraField);
6195
+ directoryRecord.bytes(rawComment);
6196
+ arraySet(directoryArray, directoryRecord.array, offset);
6197
+ offset += directoryRecordLength;
5727
6198
  if (options.onprogress) {
5728
6199
  try {
5729
6200
  await options.onprogress(indexFileEntry + 1, files.size, new Entry(fileEntry));
@@ -5733,36 +6204,53 @@
5733
6204
  }
5734
6205
  }
5735
6206
  await writeData(writer, directoryDiskOffset ? directoryArray.slice(directoryDiskOffset) : directoryArray);
6207
+ return { cdStartDiskNumber, cdStartDiskOffset };
6208
+ }
6209
+
6210
+ async function writeEndOfDirectoryRecord(zipWriter, comment, options, cdInfo) {
6211
+ const { writer } = zipWriter;
6212
+ const { cdStartDiskNumber, cdStartDiskOffset } = cdInfo;
6213
+ let { directoryDataLength } = cdInfo;
6214
+ let filesLength = zipWriter.files.size;
6215
+ let diskNumber = cdStartDiskNumber;
6216
+ let directoryOffset = zipWriter.offset - cdStartDiskOffset - (cdStartDiskNumber ? zipWriter.initialOffset : 0);
5736
6217
  let lastDiskNumber = writer.diskNumber;
5737
- const { availableSize } = writer;
5738
- if (availableSize < END_OF_CENTRAL_DIR_LENGTH) {
6218
+ if (writer.availableSize < END_OF_CENTRAL_DIR_LENGTH) {
5739
6219
  lastDiskNumber++;
5740
6220
  }
5741
6221
  let zip64 = getOptionValue(zipWriter, options, PROPERTY_NAME_ZIP64);
5742
- if (directoryOffset > MAX_32_BITS || directoryDataLength > MAX_32_BITS || filesLength > MAX_16_BITS || lastDiskNumber > MAX_16_BITS) {
6222
+ if (directoryOffset >= MAX_32_BITS || directoryDataLength >= MAX_32_BITS || filesLength >= MAX_16_BITS || lastDiskNumber >= MAX_16_BITS) {
5743
6223
  if (zip64 === false) {
5744
6224
  throw new Error(ERR_UNSUPPORTED_FORMAT);
5745
6225
  } else {
5746
6226
  zip64 = true;
5747
6227
  }
5748
6228
  }
5749
- const endOfdirectoryArray = new Uint8Array(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
5750
- const endOfdirectoryView = getDataView(endOfdirectoryArray);
5751
- offset = 0;
6229
+ const commentLength = getLength(comment);
6230
+ if (commentLength > MAX_16_BITS) {
6231
+ throw new Error(ERR_INVALID_COMMENT);
6232
+ }
6233
+ const endOfdirectoryRecord = createRecordWriter(zip64 ? ZIP64_END_OF_CENTRAL_DIR_TOTAL_LENGTH : END_OF_CENTRAL_DIR_LENGTH);
6234
+ if (getLength(endOfdirectoryRecord.array) + commentLength > writer.availableSize) {
6235
+ writer.availableSize = 0;
6236
+ await writeData(writer, new Uint8Array());
6237
+ }
6238
+ lastDiskNumber = writer.diskNumber;
5752
6239
  if (zip64) {
5753
- setUint32(endOfdirectoryView, 0, ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
5754
- setBigUint64(endOfdirectoryView, 4, BigInt(44));
5755
- setUint16(endOfdirectoryView, 12, 45);
5756
- setUint16(endOfdirectoryView, 14, 45);
5757
- setUint32(endOfdirectoryView, 16, lastDiskNumber);
5758
- setUint32(endOfdirectoryView, 20, diskNumber);
5759
- setBigUint64(endOfdirectoryView, 24, BigInt(filesLength));
5760
- setBigUint64(endOfdirectoryView, 32, BigInt(filesLength));
5761
- setBigUint64(endOfdirectoryView, 40, BigInt(directoryDataLength));
5762
- setBigUint64(endOfdirectoryView, 48, BigInt(directoryOffset));
5763
- setUint32(endOfdirectoryView, 56, ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
5764
- setBigUint64(endOfdirectoryView, 64, BigInt(directoryOffset) + BigInt(directoryDataLength));
5765
- setUint32(endOfdirectoryView, 72, lastDiskNumber + 1);
6240
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_SIGNATURE);
6241
+ endOfdirectoryRecord.uint64(44);
6242
+ endOfdirectoryRecord.uint16(45);
6243
+ endOfdirectoryRecord.uint16(45);
6244
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6245
+ endOfdirectoryRecord.uint32(diskNumber);
6246
+ endOfdirectoryRecord.uint64(filesLength);
6247
+ endOfdirectoryRecord.uint64(filesLength);
6248
+ endOfdirectoryRecord.uint64(directoryDataLength);
6249
+ endOfdirectoryRecord.uint64(directoryOffset);
6250
+ endOfdirectoryRecord.uint32(ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE);
6251
+ endOfdirectoryRecord.uint32(lastDiskNumber);
6252
+ endOfdirectoryRecord.uint64(BigInt(zipWriter.offset) + BigInt(directoryDataLength) - BigInt(writer.diskOffset) - BigInt(writer.diskNumber ? zipWriter.initialOffset : 0));
6253
+ endOfdirectoryRecord.uint32(lastDiskNumber + 1);
5766
6254
  const supportZip64SplitFile = getOptionValue(zipWriter, options, OPTION_SUPPORT_ZIP64_SPLIT_FILE, true);
5767
6255
  if (supportZip64SplitFile) {
5768
6256
  lastDiskNumber = MAX_16_BITS;
@@ -5771,29 +6259,40 @@
5771
6259
  filesLength = MAX_16_BITS;
5772
6260
  directoryOffset = MAX_32_BITS;
5773
6261
  directoryDataLength = MAX_32_BITS;
5774
- offset += ZIP64_END_OF_CENTRAL_DIR_LENGTH + ZIP64_END_OF_CENTRAL_DIR_LOCATOR_LENGTH;
5775
- }
5776
- setUint32(endOfdirectoryView, offset, END_OF_CENTRAL_DIR_SIGNATURE);
5777
- setUint16(endOfdirectoryView, offset + 4, lastDiskNumber);
5778
- setUint16(endOfdirectoryView, offset + 6, diskNumber);
5779
- setUint16(endOfdirectoryView, offset + 8, filesLength);
5780
- setUint16(endOfdirectoryView, offset + 10, filesLength);
5781
- setUint32(endOfdirectoryView, offset + 12, directoryDataLength);
5782
- setUint32(endOfdirectoryView, offset + 16, directoryOffset);
5783
- const commentLength = getLength(comment);
5784
- if (commentLength) {
5785
- if (commentLength <= MAX_16_BITS) {
5786
- setUint16(endOfdirectoryView, offset + 20, commentLength);
5787
- } else {
5788
- throw new Error(ERR_INVALID_COMMENT);
5789
- }
5790
6262
  }
5791
- await writeData(writer, endOfdirectoryArray);
6263
+ endOfdirectoryRecord.uint32(END_OF_CENTRAL_DIR_SIGNATURE);
6264
+ endOfdirectoryRecord.uint16(lastDiskNumber);
6265
+ endOfdirectoryRecord.uint16(diskNumber);
6266
+ endOfdirectoryRecord.uint16(filesLength);
6267
+ endOfdirectoryRecord.uint16(filesLength);
6268
+ endOfdirectoryRecord.uint32(directoryDataLength);
6269
+ endOfdirectoryRecord.uint32(directoryOffset);
6270
+ endOfdirectoryRecord.uint16(commentLength);
6271
+ await writeData(writer, endOfdirectoryRecord.array);
5792
6272
  if (commentLength) {
5793
6273
  await writeData(writer, comment);
5794
6274
  }
5795
6275
  }
5796
6276
 
6277
+ function createRecordWriter(length) {
6278
+ const array = new Uint8Array(length);
6279
+ const view = getDataView(array);
6280
+ let offset = 0;
6281
+ return {
6282
+ array,
6283
+ uint8: value => { setUint8(view, offset, value); offset += 1; },
6284
+ uint16: value => { setUint16(view, offset, value); offset += 2; },
6285
+ uint32: value => { setUint32(view, offset, value); offset += 4; },
6286
+ uint64: value => { setBigUint64(view, offset, BigInt(value)); offset += 8; },
6287
+ bytes: value => { arraySet(array, value, offset); offset += getLength(value); },
6288
+ skip: count => offset += count
6289
+ };
6290
+ }
6291
+
6292
+ function getSegmentOffset(zipWriter, writer) {
6293
+ return zipWriter.offset - writer.diskOffset - (writer.diskNumber ? zipWriter.initialOffset : 0);
6294
+ }
6295
+
5797
6296
  async function writeData(writer, array) {
5798
6297
  const { writable } = writer;
5799
6298
  const streamWriter = writable.getWriter();
@@ -5806,12 +6305,40 @@
5806
6305
  }
5807
6306
  }
5808
6307
 
6308
+ async function flushBufferedData(readable, writer, signal, onChunkWritten) {
6309
+ const streamWriter = writer.writable.getWriter();
6310
+ try {
6311
+ await readable.pipeTo(new WritableStream({
6312
+ async write(chunk) {
6313
+ await streamWriter.ready;
6314
+ await streamWriter.write(chunk);
6315
+ onChunkWritten(getLength(chunk));
6316
+ }
6317
+ }), { preventClose: true, preventAbort: true, signal });
6318
+ } finally {
6319
+ streamWriter.releaseLock();
6320
+ }
6321
+ }
6322
+
5809
6323
  function getTimeNTFS(date) {
5810
6324
  if (date) {
5811
6325
  return ((BigInt(date.getTime()) + BigInt(11644473600000)) * BigInt(10000));
5812
6326
  }
5813
6327
  }
5814
6328
 
6329
+ function getTimeUnix(date) {
6330
+ return Math.floor(date.getTime() / 1000);
6331
+ }
6332
+
6333
+ // the extended timestamp extra field stores dates as signed 32-bit time_t values
6334
+ function inUnixTimeRange(timeUnix) {
6335
+ return timeUnix >= MIN_UNIX_TIME && timeUnix <= MAX_UNIX_TIME;
6336
+ }
6337
+
6338
+ function clampUnixTime(timeUnix) {
6339
+ return Math.min(MAX_UNIX_TIME, Math.max(MIN_UNIX_TIME, timeUnix));
6340
+ }
6341
+
5815
6342
  function getOptionValue(zipWriter, options, name, defaultValue) {
5816
6343
  const result = options[name] === UNDEFINED_VALUE ? zipWriter.options[name] : options[name];
5817
6344
  return result === UNDEFINED_VALUE ? defaultValue : result;
@@ -5842,7 +6369,7 @@
5842
6369
  }
5843
6370
 
5844
6371
  function getDataView(array) {
5845
- return new DataView(array.buffer);
6372
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
5846
6373
  }
5847
6374
 
5848
6375
  function getLength(...arrayLikes) {
@@ -5858,30 +6385,39 @@
5858
6385
  uncompressedSize,
5859
6386
  compressedSize,
5860
6387
  lastModDate,
6388
+ rawLastModDate,
5861
6389
  rawFilename,
5862
6390
  zip64CompressedSize,
5863
6391
  zip64UncompressedSize,
5864
6392
  extraFieldLength
5865
6393
  }) {
5866
- const headerArray = new Uint8Array(HEADER_SIZE - 4);
6394
+ const headerRecord = createRecordWriter(HEADER_SIZE - 4);
6395
+ const headerArray = headerRecord.array;
5867
6396
  const headerView = getDataView(headerArray);
5868
- setUint16(headerView, 0, version);
5869
- setUint16(headerView, 2, bitFlag);
5870
- setUint16(headerView, 4, compressionMethod);
5871
- const dateArray = new Uint32Array(1);
5872
- const dateView = getDataView(dateArray);
5873
- setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
5874
- setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
5875
- const rawLastModDate = dateArray[0];
5876
- setUint32(headerView, 6, rawLastModDate);
6397
+ headerRecord.uint16(version);
6398
+ headerRecord.uint16(bitFlag);
6399
+ headerRecord.uint16(compressionMethod);
6400
+ if (rawLastModDate === UNDEFINED_VALUE) {
6401
+ const dateArray = new Uint32Array(1);
6402
+ const dateView = getDataView(dateArray);
6403
+ setUint16(dateView, 0, (((lastModDate.getHours() << 6) | lastModDate.getMinutes()) << 5) | lastModDate.getSeconds() / 2);
6404
+ setUint16(dateView, 2, ((((lastModDate.getFullYear() - 1980) << 4) | (lastModDate.getMonth() + 1)) << 5) | lastModDate.getDate());
6405
+ rawLastModDate = dateArray[0];
6406
+ }
6407
+ headerRecord.uint32(rawLastModDate);
6408
+ headerRecord.skip(4);
5877
6409
  if (zip64CompressedSize || compressedSize !== UNDEFINED_VALUE) {
5878
- setUint32(headerView, HEADER_OFFSET_COMPRESSED_SIZE, zip64CompressedSize ? MAX_32_BITS : compressedSize);
6410
+ headerRecord.uint32(zip64CompressedSize ? MAX_32_BITS : compressedSize);
6411
+ } else {
6412
+ headerRecord.skip(4);
5879
6413
  }
5880
6414
  if (zip64UncompressedSize || uncompressedSize !== UNDEFINED_VALUE) {
5881
- setUint32(headerView, HEADER_OFFSET_UNCOMPRESSED_SIZE, zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6415
+ headerRecord.uint32(zip64UncompressedSize ? MAX_32_BITS : uncompressedSize);
6416
+ } else {
6417
+ headerRecord.skip(4);
5882
6418
  }
5883
- setUint16(headerView, 22, getLength(rawFilename));
5884
- setUint16(headerView, 24, extraFieldLength);
6419
+ headerRecord.uint16(getLength(rawFilename));
6420
+ headerRecord.uint16(extraFieldLength);
5885
6421
  return {
5886
6422
  headerArray,
5887
6423
  headerView,
@@ -5982,7 +6518,7 @@
5982
6518
  // ignored
5983
6519
  }
5984
6520
 
5985
- const A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";function g(g){let B;g({wasmURI:()=>(B||(B="data:application/wasm;base64,"+(g=>{g=(g=>{const B=(g=(g+"").replace(/[^A-Za-z0-9+/=]/g,"")).length,E=[];for(let I=0;B>I;I+=4){const B=A.indexOf(g[I])<<18|A.indexOf(g[I+1])<<12|(63&A.indexOf(g[I+2]))<<6|63&A.indexOf(g[I+3]);E.push(B>>16&255),"="!==g[I+2]&&E.push(B>>8&255),"="!==g[I+3]&&E.push(255&B);}return new Uint8Array(E)})(g);let B=new Uint8Array(1024),E=0;for(let A=0;A<g.length;){const C=g[A++];if(128&C){const Q=3+(127&C),D=g[A++]<<8|g[A++],o=E-D;I(E+Q);for(let A=0;Q>A;A++)B[E++]=B[o+A];}else {const Q=C;I(E+Q);for(let I=0;Q>I&&A<g.length;I++)B[E++]=g[A++];}}return (g=>{let B="";const E=g.length;let I=0;for(;E>I+2;I+=3){const E=g[I]<<16|g[I+1]<<8|g[I+2];B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+A[63&E];}const C=E-I;if(1===C){const E=g[I]<<16;B+=A[E>>18&63]+A[E>>12&63]+"==";}else if(2===C){const E=g[I]<<16|g[I+1]<<8;B+=A[E>>18&63]+A[E>>12&63]+A[E>>6&63]+"=";}return B})(new Uint8Array(B.buffer.slice(0,E)));function I(A){if(B.length<A){let g=2*B.length;for(;A>g;)g*=2;const I=new Uint8Array(g);I.set(B.subarray(0,E)),B=I;}}})("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BAGZgAAEAVmAAAQB2YAABAE5gAAEAbmAAAQBeYAABAH5gAAEAQWAAAQBhYAABAFFgAAEAcWAAAQBJYAABAGlgAAEAWWAAAQB5YAABAEVgAAEAZWAAAQBVYAABAHVgAAEATWAAAQBtYAABAF1gAAEAfWAAAQBDYAABAGNgAAEAU2AAAQBzYAABIARMwIArYAABAFtgAAEAe2AAAQBHYAABAGdgAAEAV2AAAQB3YAABAE9gAAEAb2AAAQBfYAABAH9gAAEAROAAMIFEwEJAJOAAAgBk4AACAFTgAAIAVOAAAgB04AACAHTgAAIATOAAAgBM4AACAGzgAAIAbOAAAgBc4AACAFzgAAIAfOAAAgB84AACAELgAAIgBDagAQCgAAEgAAIAUuAAAgBS4AACAHLgAAIAcuAAAgBK4AACAErgAAIAauAAAgBq4AACAFrgAAIAWuAAAgB64AACAHrgAAIARuAAAgBG4AACAGbgAAIAZuAAAgBW4AACAFbgAAIAduAAAgB24AACAE7gAAIATuAAAgBu4AACAG7gAAIAXuAAAgBe4AACAH7gAAIAfuAAAiBA7YBB4AACAGHgAAIAYeAAAgBR4AACAFHgAAIAceAAAgBx4AACAEngAAIASeAAAgBp4AACAGngAAIAWeAAAgBZ4AACAHngAAIAeeAAAgBF4AACAEXgAAIAZeAAAgBl4AACAFXgAAIAVeAAAgB14AACAHXgAAIATeAAAgBN4AACAG3gAAIAbeAAAgBd4AACAF3gAAIAfeAAAgB94AACAEPgAAIAQ+AAAgBj4AACAGPgAAIAU+AAAgBT4AACAHPgAAIAc+AAAgBL4AACAEvgAAIAa+AAAgBr4AACAFvgAAIAW+AAAgB74AACAHvgAAIAR+AAAgBH4AACAGfgAAIAZ+AAAgBX4AACAFfgAAIAd+AAAgB34AACAE/gAAIAT+AAAgBv4AACAG/gAAIAX+AAAgBf4AACAH/gAAIAf+AAAiBBAoBQIAABAEggAAEAWCAAAQBEIAABAFQgAAEATCAAAQBcIIFVgMHAEiAAAQBKIAABAFogAAEARiAAAQBWIAABAE4gAAEAXiAAAQBBIAABAFEgAAEASSAAAQBZIAABAEUgAAEAVSAAAQBNIAABAF0gAAEAQOAAEIBg4AABAFDgAAEAcOAAAQBI4AABAGjgAAEAWOAAAQB44AABIC+K4AAdIECxgEFgABcAQWCBUoBFIAABAEMgAAEARyAAASAvlaABEQBBYIGBAEaggXqAQWAA9QBBYADuAEFgAOcgE92gAAEARGAAAQBCYAABAEZgAAEgQACARWAAAQBDYAABAEdgAAEgL59gAKkgQZAAQWAAiyBBaYBBYABtAEFgD3fAxsLTYMfuYcABIC+rooABIEHUYkABAEEjAAEAQWKAAQEQbAcC4C9CosAS40AO4UALwEGhAAEgQWIgQAEgQEKgQAEgQGSgQAEgIS2ggAEAQuEAAQBDIQABIAF24FHeQTgHQsjhQBfhQXLAhARgAVtBgcJBgoFC4A6uAQNAg4BgAclBJQeC2mFAJCFAIiFAICFAHiBAGiBAFyBBh8BEIAABAEUgAAEARiAAAQBHIAABAEggAAEASiAAAQBMIAABAE4gAAEAUCAAAQBUIAABIEGvQFwgAAEAYCAAAQBoIAABAHAgAAEAeCAAG8DHwtyjQBvgQBrgQBngQBjgQBfgQBbgQBXgQBTgQBPgQBLgQBHgQBDgQE8AYCvAEGAUc0CC22BAMcBBIAAAgEIgAAEgQEzgQJLARCAAA6DAAyBnqyAqmuEACSBB3OBAE8BCIAACIEAGIUADIEIt4MADAEggQCUgDKEgQBrAYCBCC8BBIMADIA/SAoBABAMAEGRIQv/gCUfgMDAgIKxBQgJCQoKgEk3gAABAQ2AAAEBDoAAAQEPgAABARCEAAEBEYQAAQEShAABAROEAAEBFIwAAQEVjAABARaMAAEBF4wAAQEYnAABARmcAAEBGpwAAQEbmwABARyBffsEBAQFBYHB1QEHgAABAQiEAAGAXSqCAAEBCowAAYAnsooAAYEBMJkAAYEBTJkAAYEBaLkAAYEBpLkAAYIDdYABzoUBvI0BqJ0BkLwBgAIbHLwAAQEdvAABgA9PgH05A9AqAQ==")),B)});}
6521
+ 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)});}
5986
6522
 
5987
6523
  /*
5988
6524
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -6032,46 +6568,54 @@
6032
6568
 
6033
6569
  return new TransformStream({
6034
6570
  start() {
6035
- let result;
6036
- this.out = malloc(outBufferSize);
6037
- this.in = malloc(inBufferSize);
6038
- this.inBufferSize = inBufferSize;
6039
- this._scratch = new Uint8Array(outBufferSize);
6040
- if (isCompress) {
6041
- this._process = wasm.deflate_process;
6042
- this._last_consumed = wasm.deflate_last_consumed;
6043
- this._end = wasm.deflate_end;
6044
- this.streamHandle = wasm.deflate_new();
6045
- if (type === "gzip") {
6046
- result = wasm.deflate_init_gzip(this.streamHandle, level);
6047
- } else if (type === "deflate-raw") {
6048
- result = wasm.deflate_init_raw(this.streamHandle, level);
6049
- } else {
6050
- result = wasm.deflate_init(this.streamHandle, level);
6571
+ try {
6572
+ let result;
6573
+ this.out = malloc(outBufferSize);
6574
+ this.in = malloc(inBufferSize);
6575
+ this.inBufferSize = inBufferSize;
6576
+ if (!this.out || !this.in) {
6577
+ throw new Error("allocation failed");
6051
6578
  }
6052
- } else {
6053
- if (type === "deflate64-raw") {
6054
- this._process = wasm.inflate9_process;
6055
- this._last_consumed = wasm.inflate9_last_consumed;
6056
- this._end = wasm.inflate9_end;
6057
- this.streamHandle = wasm.inflate9_new();
6058
- result = wasm.inflate9_init_raw(this.streamHandle);
6579
+ this._scratch = new Uint8Array(outBufferSize);
6580
+ if (isCompress) {
6581
+ this._process = wasm.deflate_process;
6582
+ this._last_consumed = wasm.deflate_last_consumed;
6583
+ this._end = wasm.deflate_end;
6584
+ this.streamHandle = wasm.deflate_new();
6585
+ if (type === "gzip") {
6586
+ result = wasm.deflate_init_gzip(this.streamHandle, level);
6587
+ } else if (type === "deflate-raw") {
6588
+ result = wasm.deflate_init_raw(this.streamHandle, level);
6589
+ } else {
6590
+ result = wasm.deflate_init(this.streamHandle, level);
6591
+ }
6059
6592
  } else {
6060
- this._process = wasm.inflate_process;
6061
- this._last_consumed = wasm.inflate_last_consumed;
6062
- this._end = wasm.inflate_end;
6063
- this.streamHandle = wasm.inflate_new();
6064
- if (type === "deflate-raw") {
6065
- result = wasm.inflate_init_raw(this.streamHandle);
6066
- } else if (type === "gzip") {
6067
- result = wasm.inflate_init_gzip(this.streamHandle);
6593
+ if (type === "deflate64-raw") {
6594
+ this._process = wasm.inflate9_process;
6595
+ this._last_consumed = wasm.inflate9_last_consumed;
6596
+ this._end = wasm.inflate9_end;
6597
+ this.streamHandle = wasm.inflate9_new();
6598
+ result = wasm.inflate9_init_raw(this.streamHandle);
6068
6599
  } else {
6069
- result = wasm.inflate_init(this.streamHandle);
6600
+ this._process = wasm.inflate_process;
6601
+ this._last_consumed = wasm.inflate_last_consumed;
6602
+ this._end = wasm.inflate_end;
6603
+ this.streamHandle = wasm.inflate_new();
6604
+ if (type === "deflate-raw") {
6605
+ result = wasm.inflate_init_raw(this.streamHandle);
6606
+ } else if (type === "gzip") {
6607
+ result = wasm.inflate_init_gzip(this.streamHandle);
6608
+ } else {
6609
+ result = wasm.inflate_init(this.streamHandle);
6610
+ }
6070
6611
  }
6071
6612
  }
6072
- }
6073
- if (result !== 0) {
6074
- throw new Error("init failed:" + result);
6613
+ if (result !== 0) {
6614
+ throw new Error("init failed:" + result);
6615
+ }
6616
+ } catch (error) {
6617
+ disposeStream(this);
6618
+ throw error;
6075
6619
  }
6076
6620
  },
6077
6621
  transform(chunk, controller) {
@@ -6088,9 +6632,13 @@
6088
6632
  if (!this.in || this.inBufferSize < toRead) {
6089
6633
  if (this.in && free) {
6090
6634
  free(this.in);
6635
+ this.in = 0;
6091
6636
  }
6092
6637
  this.in = malloc(toRead);
6093
6638
  this.inBufferSize = toRead;
6639
+ if (!this.in) {
6640
+ throw new Error("allocation failed");
6641
+ }
6094
6642
  }
6095
6643
  heap.set(buffer.subarray(offset, offset + toRead), this.in);
6096
6644
  const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
@@ -6113,15 +6661,7 @@
6113
6661
  offset += consumed;
6114
6662
  }
6115
6663
  } catch (error) {
6116
- if (this._end && this.streamHandle) {
6117
- this._end(this.streamHandle);
6118
- }
6119
- if (this.in && free) {
6120
- free(this.in);
6121
- }
6122
- if (this.out && free) {
6123
- free(this.out);
6124
- }
6664
+ disposeStream(this);
6125
6665
  controller.error(error);
6126
6666
  }
6127
6667
  },
@@ -6152,21 +6692,35 @@
6152
6692
  } catch (error) {
6153
6693
  controller.error(error);
6154
6694
  } finally {
6155
- if (this._end && this.streamHandle) {
6156
- const result = this._end(this.streamHandle);
6157
- if (result !== 0) {
6158
- controller.error(new Error("end error:" + result));
6159
- }
6160
- }
6161
- if (this.in && free) {
6162
- free(this.in);
6163
- }
6164
- if (this.out && free) {
6165
- free(this.out);
6695
+ const result = disposeStream(this);
6696
+ if (result !== 0) {
6697
+ controller.error(new Error("end error:" + result));
6166
6698
  }
6167
6699
  }
6700
+ },
6701
+ cancel() {
6702
+ // release the stream handle and buffers when the pipeline is aborted,
6703
+ // they would be leaked in the process-lifetime wasm heap otherwise
6704
+ disposeStream(this);
6168
6705
  }
6169
6706
  });
6707
+
6708
+ function disposeStream(state) {
6709
+ let endResult = 0;
6710
+ if (state.streamHandle && state._end) {
6711
+ endResult = state._end(state.streamHandle);
6712
+ }
6713
+ state.streamHandle = 0;
6714
+ if (state.in && free) {
6715
+ free(state.in);
6716
+ }
6717
+ state.in = 0;
6718
+ if (state.out && free) {
6719
+ free(state.out);
6720
+ }
6721
+ state.out = 0;
6722
+ return endResult;
6723
+ }
6170
6724
  }
6171
6725
 
6172
6726
  class CompressionStreamZlib {
@@ -6179,6 +6733,11 @@
6179
6733
  return _make(false, type, options);
6180
6734
  }
6181
6735
  }
6736
+ // These codecs are backed by the WASM module; they are unusable until setWasmExports() has run.
6737
+ // The worker uses this flag to know it must fall back to the native CompressionStream when the
6738
+ // module fails to load, rather than discarding a self-contained codec supplied through config.
6739
+ CompressionStreamZlib.requiresModule = true;
6740
+ DecompressionStreamZlib.requiresModule = true;
6182
6741
 
6183
6742
  /*
6184
6743
  Copyright (c) 2025 Gildas Lormeau. All rights reserved.
@@ -6336,12 +6895,15 @@
6336
6895
  */
6337
6896
 
6338
6897
 
6898
+ const ERR_ENTRY_EXISTS = "Entry filename already exists";
6899
+ const ERR_READABLE_CONSUMED = "Readable stream already consumed";
6900
+
6339
6901
  class ZipEntry {
6340
6902
 
6341
6903
  constructor(fs, name, params, parent) {
6342
6904
  const zipEntry = this;
6343
6905
  if (fs.root && parent && parent.getChildByName(name)) {
6344
- throw new Error("Entry filename already exists");
6906
+ throw new Error(ERR_ENTRY_EXISTS);
6345
6907
  }
6346
6908
  if (!params) {
6347
6909
  params = {};
@@ -6351,13 +6913,17 @@
6351
6913
  name,
6352
6914
  data: params.data,
6353
6915
  options: params.options,
6354
- id: fs.entries.length,
6916
+ id: fs.entryIdCounter++,
6355
6917
  parent,
6356
6918
  children: [],
6357
6919
  uncompressedSize: params.uncompressedSize || 0,
6358
6920
  passThrough: params.passThrough
6359
6921
  });
6360
- fs.entries.push(zipEntry);
6922
+ // detached entries (e.g. clones) are not registered until they are attached,
6923
+ // otherwise they could never be garbage collected
6924
+ if (parent || !fs.root) {
6925
+ fs.entries[zipEntry.id] = zipEntry;
6926
+ }
6361
6927
  if (parent) {
6362
6928
  zipEntry.parent.children.push(zipEntry);
6363
6929
  }
@@ -6395,7 +6961,7 @@
6395
6961
  rename(name) {
6396
6962
  const parent = this.parent;
6397
6963
  if (parent && parent.getChildByName(name)) {
6398
- throw new Error("Entry filename already exists");
6964
+ throw new Error(ERR_ENTRY_EXISTS);
6399
6965
  } else {
6400
6966
  this.name = name;
6401
6967
  }
@@ -6434,16 +7000,17 @@
6434
7000
  }
6435
7001
 
6436
7002
  isPasswordProtected() {
6437
- return this.data.encrypted;
7003
+ return Boolean(this.data && this.data.encrypted);
6438
7004
  }
6439
7005
 
6440
7006
  async checkPassword(password, options = {}) {
6441
7007
  const zipEntry = this;
6442
7008
  if (zipEntry.isPasswordProtected()) {
6443
- options.password = password;
6444
- options.checkPasswordOnly = true;
6445
7009
  try {
6446
- await zipEntry.data.getData(null, options);
7010
+ await zipEntry.data.getData(null, Object.assign({}, options, {
7011
+ password,
7012
+ checkPasswordOnly: true
7013
+ }));
6447
7014
  return true;
6448
7015
  } catch (error) {
6449
7016
  if (error.message == ERR_INVALID_PASSWORD) {
@@ -6477,8 +7044,15 @@
6477
7044
  return this.getData({ writable }, options);
6478
7045
  }
6479
7046
 
6480
- getArrayBuffer(options) {
6481
- return this.data.arrayBuffer(options);
7047
+ async getArrayBuffer(options) {
7048
+ // this.data may be a string, a Uint8Array, a data URI or a Blob depending on how the entry
7049
+ // was created, so retrieve the bytes through getUint8Array rather than assuming a Blob; this
7050
+ // also applies the options (password, signal, onprogress...) like the other getData() getters
7051
+ const array = await this.getUint8Array(options);
7052
+ // return the backing buffer directly when the array spans it, slicing the exact bytes otherwise
7053
+ return array.byteOffset || array.byteLength != array.buffer.byteLength
7054
+ ? array.buffer.slice(array.byteOffset, array.byteOffset + array.byteLength)
7055
+ : array.buffer;
6482
7056
  }
6483
7057
 
6484
7058
  replaceBlob(blob) {
@@ -6520,7 +7094,7 @@
6520
7094
  replaceReadable(readable) {
6521
7095
  Object.assign(this, {
6522
7096
  data: null,
6523
- Reader: function () { return { readable }; },
7097
+ Reader: getReadableReader(readable),
6524
7098
  Writer: null,
6525
7099
  reader: null
6526
7100
  });
@@ -6536,7 +7110,7 @@
6536
7110
 
6537
7111
  clone(deepClone) {
6538
7112
  const zipEntry = this;
6539
- const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name);
7113
+ const clonedEntry = new ZipDirectoryEntry(zipEntry.fs, zipEntry.name, zipEntry);
6540
7114
  if (deepClone) {
6541
7115
  clonedEntry.children = zipEntry.children.map(child => {
6542
7116
  const childClone = child.clone(deepClone);
@@ -6610,7 +7184,7 @@
6610
7184
 
6611
7185
  addReadable(name, readable, options = {}) {
6612
7186
  return addChild(this, name, {
6613
- Reader: function () { return { readable }; },
7187
+ Reader: getReadableReader(readable),
6614
7188
  options
6615
7189
  });
6616
7190
  }
@@ -6624,6 +7198,7 @@
6624
7198
  }
6625
7199
 
6626
7200
  addFile(file, options = {}) {
7201
+ options = Object.assign({}, options);
6627
7202
  if (!options.lastModDate) {
6628
7203
  options.lastModDate = new Date(file.lastModified);
6629
7204
  }
@@ -6690,11 +7265,15 @@
6690
7265
  try {
6691
7266
  const path = entry.filename.split("/");
6692
7267
  const name = path.pop();
6693
- path.forEach((pathPart, pathIndex) => {
7268
+ path.forEach(pathPart => {
6694
7269
  const previousParent = parent;
6695
7270
  parent = parent.getChildByName(pathPart);
6696
- if (!parent) {
6697
- parent = new ZipDirectoryEntry(this.fs, pathPart, { data: pathIndex == path.length - 1 ? entry : null }, previousParent);
7271
+ if (parent) {
7272
+ if (!parent.directory) {
7273
+ throw new Error(ERR_ENTRY_EXISTS);
7274
+ }
7275
+ } else {
7276
+ parent = new ZipDirectoryEntry(this.fs, pathPart, { data: null }, previousParent);
6698
7277
  importedEntries.push(parent);
6699
7278
  }
6700
7279
  });
@@ -6705,6 +7284,22 @@
6705
7284
  uncompressedSize: entry.uncompressedSize,
6706
7285
  passThrough: options.passThrough
6707
7286
  }));
7287
+ } else {
7288
+ let directoryEntry = parent;
7289
+ if (name) {
7290
+ directoryEntry = parent.getChildByName(name);
7291
+ if (directoryEntry) {
7292
+ if (!directoryEntry.directory) {
7293
+ throw new Error(ERR_ENTRY_EXISTS);
7294
+ }
7295
+ } else {
7296
+ directoryEntry = new ZipDirectoryEntry(this.fs, name, { data: null }, parent);
7297
+ importedEntries.push(directoryEntry);
7298
+ }
7299
+ }
7300
+ if (directoryEntry != this && !directoryEntry.data) {
7301
+ directoryEntry.data = entry;
7302
+ }
6708
7303
  }
6709
7304
  } catch (error) {
6710
7305
  try {
@@ -6720,14 +7315,15 @@
6720
7315
  return importedEntries;
6721
7316
  }
6722
7317
 
6723
- async exportZip(writer, options) {
7318
+ async exportZip(writer, options = {}) {
6724
7319
  const zipEntry = this;
7320
+ options = Object.assign({}, options);
6725
7321
  if (options.bufferedWrite === UNDEFINED_VALUE) {
6726
7322
  options.bufferedWrite = true;
6727
7323
  }
6728
- await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
7324
+ const [readers] = await Promise.all([initReaders(zipEntry, options.readerOptions), initStream(writer)]);
6729
7325
  const zipWriter = new ZipWriter(writer, options);
6730
- await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options);
7326
+ await exportZip(zipWriter, zipEntry, getTotalSize([zipEntry], "uncompressedSize"), options, readers);
6731
7327
  await zipWriter.close();
6732
7328
  return writer.getData ? writer.getData() : writer.writable;
6733
7329
  }
@@ -6773,7 +7369,15 @@
6773
7369
 
6774
7370
  remove(entry) {
6775
7371
  detach(entry);
6776
- this.entries[entry.id] = null;
7372
+ const removedEntries = [entry];
7373
+ while (removedEntries.length) {
7374
+ const removedEntry = removedEntries.pop();
7375
+ this.entries[removedEntry.id] = null;
7376
+ for (const child of removedEntry.children) {
7377
+ removedEntries.push(child);
7378
+ }
7379
+ }
7380
+ entry.parent = UNDEFINED_VALUE;
6777
7381
  }
6778
7382
 
6779
7383
  move(entry, destination) {
@@ -6783,12 +7387,17 @@
6783
7387
  if (destination.directory) {
6784
7388
  if (!destination.isDescendantOf(entry)) {
6785
7389
  if (entry != destination) {
6786
- if (destination.getChildByName(entry.name)) {
6787
- throw new Error("Entry filename already exists");
7390
+ const existingChild = destination.getChildByName(entry.name);
7391
+ if (existingChild) {
7392
+ if (existingChild != entry) {
7393
+ throw new Error(ERR_ENTRY_EXISTS);
7394
+ }
7395
+ } else {
7396
+ detach(entry);
7397
+ entry.parent = destination;
7398
+ destination.children.push(entry);
7399
+ registerEntries(this, entry);
6788
7400
  }
6789
- detach(entry);
6790
- entry.parent = destination;
6791
- destination.children.push(entry);
6792
7401
  }
6793
7402
  } else {
6794
7403
  throw new Error("Entry is a ancestor of target entry");
@@ -6805,6 +7414,11 @@
6805
7414
  for (let index = 0; node && index < path.length; index++) {
6806
7415
  node = node.getChildByName(path[index]);
6807
7416
  }
7417
+ if (!node) {
7418
+ // exclude detached entries, e.g. clones registered in `entries` but not attached
7419
+ node = this.entries.find(entry => entry && (entry == this.root || entry.isDescendantOf(this.root)) &&
7420
+ entry.getRelativeName() == fullname);
7421
+ }
6808
7422
  return node;
6809
7423
  }
6810
7424
 
@@ -6886,6 +7500,7 @@
6886
7500
  }
6887
7501
 
6888
7502
  importZip(reader, options) {
7503
+ resetFS(this);
6889
7504
  return this.root.importZip(reader, options);
6890
7505
  }
6891
7506
 
@@ -6905,6 +7520,10 @@
6905
7520
  return this.root.exportWritable(writable, options);
6906
7521
  }
6907
7522
 
7523
+ exportZip(writer, options) {
7524
+ return this.root.exportZip(writer, options);
7525
+ }
7526
+
6908
7527
  isPasswordProtected() {
6909
7528
  return this.root.isPasswordProtected();
6910
7529
  }
@@ -6918,15 +7537,26 @@
6918
7537
 
6919
7538
  function getTotalSize(entries, propertyName) {
6920
7539
  let size = 0;
6921
- entries.forEach(process);
7540
+ const pendingEntries = Array.from(entries);
7541
+ while (pendingEntries.length) {
7542
+ const entry = pendingEntries.pop();
7543
+ size += entry[propertyName] || 0;
7544
+ for (const child of entry.children) {
7545
+ pendingEntries.push(child);
7546
+ }
7547
+ }
6922
7548
  return size;
7549
+ }
6923
7550
 
6924
- function process(entry) {
6925
- size += entry[propertyName];
6926
- if (entry.children) {
6927
- entry.children.forEach(process);
7551
+ function getReadableReader(readable) {
7552
+ let consumed;
7553
+ return function () {
7554
+ if (consumed) {
7555
+ throw new Error(ERR_READABLE_CONSUMED);
6928
7556
  }
6929
- }
7557
+ consumed = true;
7558
+ return { readable };
7559
+ };
6930
7560
  }
6931
7561
 
6932
7562
  function getZipBlobReader(options) {
@@ -6941,7 +7571,7 @@
6941
7571
  async init() {
6942
7572
  const zipBlobReader = this;
6943
7573
  zipBlobReader.size = zipBlobReader.entry.uncompressedSize;
6944
- const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, zipBlobReader.options, options));
7574
+ const data = await zipBlobReader.entry.getData(new BlobWriter(), Object.assign({}, options, zipBlobReader.options));
6945
7575
  zipBlobReader.data = data;
6946
7576
  zipBlobReader.blobReader = new BlobReader(data);
6947
7577
  super.init();
@@ -6954,29 +7584,41 @@
6954
7584
  }
6955
7585
 
6956
7586
  async function initReaders(entry, options) {
6957
- if (entry.children.length) {
6958
- await Promise.all(entry.children.map(async child => {
7587
+ const fileEntries = [];
7588
+ const pendingEntries = [entry];
7589
+ // per-export map so concurrent exports do not share (and lock) the same readers
7590
+ const readers = new Map();
7591
+ while (pendingEntries.length) {
7592
+ const pendingEntry = pendingEntries.pop();
7593
+ for (const child of pendingEntry.children) {
6959
7594
  if (child.directory) {
6960
- await initReaders(child, options);
7595
+ pendingEntries.push(child);
6961
7596
  } else {
6962
- const reader = child.reader = new child.Reader(child.data, options);
6963
- try {
6964
- await initStream(reader);
6965
- } catch (error) {
6966
- try {
6967
- error.entryId = child.id;
6968
- error.cause = {
6969
- entry: child
6970
- };
6971
- } catch {
6972
- // ignored
6973
- }
6974
- throw error;
6975
- }
6976
- child.uncompressedSize = reader.size;
7597
+ fileEntries.push(child);
6977
7598
  }
6978
- }));
7599
+ }
6979
7600
  }
7601
+ await Promise.all(fileEntries.map(async child => {
7602
+ const reader = child.reader = new child.Reader(child.data, options);
7603
+ readers.set(child, reader);
7604
+ try {
7605
+ await initStream(reader);
7606
+ } catch (error) {
7607
+ try {
7608
+ error.entryId = child.id;
7609
+ error.cause = {
7610
+ entry: child
7611
+ };
7612
+ } catch {
7613
+ // ignored
7614
+ }
7615
+ throw error;
7616
+ }
7617
+ if (reader.size !== UNDEFINED_VALUE) {
7618
+ child.uncompressedSize = reader.size;
7619
+ }
7620
+ }));
7621
+ return readers;
6980
7622
  }
6981
7623
 
6982
7624
  function detach(entry) {
@@ -6990,7 +7632,7 @@
6990
7632
  }
6991
7633
  }
6992
7634
 
6993
- async function exportZip(zipWriter, entry, totalSize, options) {
7635
+ async function exportZip(zipWriter, entry, totalSize, options, readers) {
6994
7636
  const selectedEntry = entry;
6995
7637
  const entryOffsets = new Map();
6996
7638
  await process(zipWriter, entry);
@@ -7000,7 +7642,11 @@
7000
7642
 
7001
7643
  async function exportChild() {
7002
7644
  if (options.bufferedWrite) {
7003
- await Promise.allSettled(entry.children.map(processChild));
7645
+ const results = await Promise.allSettled(entry.children.map(processChild));
7646
+ const errorResult = results.find(result => result.status == "rejected");
7647
+ if (errorResult) {
7648
+ throw errorResult.reason;
7649
+ }
7004
7650
  } else {
7005
7651
  for (const child of entry.children) {
7006
7652
  await processChild(child);
@@ -7055,7 +7701,7 @@
7055
7701
  });
7056
7702
  }
7057
7703
  }
7058
- await zipWriter.add(name, child.reader, Object.assign({}, options, zipEntryOptions, childOptions, {
7704
+ await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
7059
7705
  directory: child.directory,
7060
7706
  onprogress: async indexProgress => {
7061
7707
  if (options.onprogress) {
@@ -7104,7 +7750,7 @@
7104
7750
  }
7105
7751
  } catch (error) {
7106
7752
  const message = error.message + (handle ? " (" + handle.name + ")" : "");
7107
- throw new Error(message);
7753
+ throw new Error(message, { cause: error });
7108
7754
  }
7109
7755
  }
7110
7756
  return addedEntries;
@@ -7164,9 +7810,21 @@
7164
7810
 
7165
7811
  function resetFS(fs) {
7166
7812
  fs.entries = [];
7813
+ fs.entryIdCounter = 0;
7167
7814
  fs.root = new ZipDirectoryEntry(fs);
7168
7815
  }
7169
7816
 
7817
+ function registerEntries(fs, entry) {
7818
+ const pendingEntries = [entry];
7819
+ while (pendingEntries.length) {
7820
+ const pendingEntry = pendingEntries.pop();
7821
+ fs.entries[pendingEntry.id] = pendingEntry;
7822
+ for (const child of pendingEntry.children) {
7823
+ pendingEntries.push(child);
7824
+ }
7825
+ }
7826
+ }
7827
+
7170
7828
  function addChild(parent, name, params, directory) {
7171
7829
  if (parent.directory) {
7172
7830
  return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new ZipFileEntry(parent.fs, name, params, parent);
@@ -8842,6 +9500,7 @@
8842
9500
  exports.BlobWriter = BlobWriter;
8843
9501
  exports.Data64URIReader = Data64URIReader;
8844
9502
  exports.Data64URIWriter = Data64URIWriter;
9503
+ exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
8845
9504
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
8846
9505
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
8847
9506
  exports.ERR_DUPLICATED_NAME = ERR_DUPLICATED_NAME;
@@ -8851,6 +9510,7 @@
8851
9510
  exports.ERR_EXTRAFIELD_ZIP64_NOT_FOUND = ERR_EXTRAFIELD_ZIP64_NOT_FOUND;
8852
9511
  exports.ERR_HTTP_RANGE = ERR_HTTP_RANGE;
8853
9512
  exports.ERR_INVALID_COMMENT = ERR_INVALID_COMMENT;
9513
+ exports.ERR_INVALID_COMPRESSED_DATA = ERR_INVALID_COMPRESSED_DATA;
8854
9514
  exports.ERR_INVALID_ENCRYPTION_STRENGTH = ERR_INVALID_ENCRYPTION_STRENGTH;
8855
9515
  exports.ERR_INVALID_ENTRY_COMMENT = ERR_INVALID_ENTRY_COMMENT;
8856
9516
  exports.ERR_INVALID_ENTRY_NAME = ERR_INVALID_ENTRY_NAME;
@@ -8863,8 +9523,9 @@
8863
9523
  exports.ERR_LOCAL_FILE_HEADER_NOT_FOUND = ERR_LOCAL_FILE_HEADER_NOT_FOUND;
8864
9524
  exports.ERR_OVERLAPPING_ENTRY = ERR_OVERLAPPING_ENTRY;
8865
9525
  exports.ERR_SPLIT_ZIP_FILE = ERR_SPLIT_ZIP_FILE;
9526
+ exports.ERR_UNDEFINED_READER = ERR_UNDEFINED_READER;
8866
9527
  exports.ERR_UNDEFINED_UNCOMPRESSED_SIZE = ERR_UNDEFINED_UNCOMPRESSED_SIZE;
8867
- exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION;
9528
+ exports.ERR_UNSUPPORTED_COMPRESSION = ERR_UNSUPPORTED_COMPRESSION$1;
8868
9529
  exports.ERR_UNSUPPORTED_ENCRYPTION = ERR_UNSUPPORTED_ENCRYPTION;
8869
9530
  exports.ERR_UNSUPPORTED_FORMAT = ERR_UNSUPPORTED_FORMAT;
8870
9531
  exports.ERR_ZIP_NOT_EMPTY = ERR_ZIP_NOT_EMPTY;