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