@zip.js/zip.js 2.16.0 → 2.17.0
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/deno.json +1 -1
- package/dist/zip-core-external.js +429 -274
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +230 -151
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +580 -283
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +383 -160
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +580 -283
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +386 -163
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +583 -283
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +232 -153
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +233 -154
- 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 +430 -274
- package/dist/zip.min.js +1 -1
- package/eslint.config.mjs +1 -1
- package/index-native.cjs +386 -163
- package/index-native.min.js +1 -1
- package/index.cjs +583 -283
- package/index.d.cts +168 -29
- package/index.d.ts +168 -29
- package/index.min.js +1 -1
- package/lib/core/codec-pool.js +2 -0
- package/lib/core/codec-worker-web.js +11 -3
- package/lib/core/codec-worker.js +2 -1
- package/lib/core/streams/aes-crypto-stream.js +60 -17
- package/lib/core/streams/codec-stream.js +2 -0
- package/lib/core/streams/zip-crypto-stream.js +7 -7
- package/lib/core/streams/zip-entry-stream.js +130 -113
- package/lib/core/streams/zlib-js/zlib-streams.min.js +1 -1
- package/lib/core/streams/zlib-wasm/zlib-streams.js +199 -122
- package/lib/core/util/compatible-streams.js +10 -5
- package/lib/core/version.js +1 -1
- package/lib/core/web-worker-base.js +1 -1
- 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 +157 -10
- package/lib/core/zip-reader.js +8 -5
- package/lib/core/zip-writer.js +5 -2
- package/lib/zip-core-reader.js +1 -0
- package/package.json +3 -2
package/lib/core/codec-pool.js
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
ERR_INVALID_UNCOMPRESSED_SIZE,
|
|
38
38
|
ERR_INVALID_PASSWORD,
|
|
39
39
|
ERR_INVALID_COMPRESSED_DATA,
|
|
40
|
+
ERR_CODEC_OUT_OF_MEMORY,
|
|
40
41
|
ERR_ABORT_CHECK_PASSWORD,
|
|
41
42
|
ERR_UNSUPPORTED_CRYPTO_API
|
|
42
43
|
} from "./streams/codec-stream.js";
|
|
@@ -58,6 +59,7 @@ export {
|
|
|
58
59
|
ERR_INVALID_UNCOMPRESSED_SIZE,
|
|
59
60
|
ERR_INVALID_PASSWORD,
|
|
60
61
|
ERR_INVALID_COMPRESSED_DATA,
|
|
62
|
+
ERR_CODEC_OUT_OF_MEMORY,
|
|
61
63
|
ERR_ABORT_CHECK_PASSWORD,
|
|
62
64
|
ERR_UNSUPPORTED_CRYPTO_API,
|
|
63
65
|
ERR_WORKER_STARTUP_TIMEOUT
|
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
const MODULE_WORKER_OPTIONS = { type: "module" };
|
|
54
54
|
const ERROR_EVENT_TYPE = "error";
|
|
55
55
|
const MESSAGE_ERROR_EVENT_TYPE = "messageerror";
|
|
56
|
+
const ABORT_EVENT_TYPE = "abort";
|
|
56
57
|
|
|
57
58
|
let webWorkerSource, webWorkerURI, webWorkerOptions;
|
|
58
59
|
let transferStreamsSupported = true;
|
|
@@ -229,6 +230,13 @@ function watchClosedStream(writableSource, workerData) {
|
|
|
229
230
|
Object.assign(workerData, { destinationFailed: true, destinationError: error });
|
|
230
231
|
}
|
|
231
232
|
});
|
|
233
|
+
const { signal } = workerData.workerOptions.streamOptions;
|
|
234
|
+
if (signal) {
|
|
235
|
+
const onAbort = () => abortController.abort(signal.reason);
|
|
236
|
+
const removeAbortListener = () => signal.removeEventListener(ABORT_EVENT_TYPE, onAbort);
|
|
237
|
+
signal.addEventListener(ABORT_EVENT_TYPE, onAbort);
|
|
238
|
+
closed.then(removeAbortListener, removeAbortListener);
|
|
239
|
+
}
|
|
232
240
|
return {
|
|
233
241
|
writable, closed, abortPipe: () => {
|
|
234
242
|
aborting = true;
|
|
@@ -491,9 +499,6 @@ function getResponseError(errorData, errorValue) {
|
|
|
491
499
|
responseError = errorValue.value;
|
|
492
500
|
} else {
|
|
493
501
|
responseError = Object.assign(new Error(message), { stack, code, name });
|
|
494
|
-
if (cause) {
|
|
495
|
-
responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
|
|
496
|
-
}
|
|
497
502
|
}
|
|
498
503
|
if (isErrorObject(responseError)) {
|
|
499
504
|
try {
|
|
@@ -503,6 +508,9 @@ function getResponseError(errorData, errorValue) {
|
|
|
503
508
|
if (codecImportFailed) {
|
|
504
509
|
responseError.codecImportFailed = true;
|
|
505
510
|
}
|
|
511
|
+
if (cause && !isErrorObject(responseError.cause)) {
|
|
512
|
+
responseError.cause = Object.assign(new Error(cause.message), { name: cause.name });
|
|
513
|
+
}
|
|
506
514
|
if (errorValue) {
|
|
507
515
|
if (responseError.name !== name) {
|
|
508
516
|
responseError.name = name;
|
package/lib/core/codec-worker.js
CHANGED
|
@@ -231,10 +231,11 @@ async function runWorker({ options, readable, writable, onTaskFinished, workerOp
|
|
|
231
231
|
}
|
|
232
232
|
codecStream = new CodecStream(options, config);
|
|
233
233
|
chunkStream = new ChunkStream(getChunkSize(config));
|
|
234
|
+
const { signal } = workerOptions.streamOptions;
|
|
234
235
|
await readable
|
|
235
236
|
.pipeThrough(codecStream)
|
|
236
237
|
.pipeThrough(chunkStream)
|
|
237
|
-
.pipeTo(writable, { preventClose: true, preventAbort: true });
|
|
238
|
+
.pipeTo(writable, { preventClose: true, preventAbort: true, signal });
|
|
238
239
|
const {
|
|
239
240
|
crc32,
|
|
240
241
|
inputSize,
|
|
@@ -26,8 +26,7 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global crypto, TransformStream */
|
|
30
|
-
// deno-lint-ignore-file no-this-alias
|
|
29
|
+
/* global crypto, TransformStream, ReadableStream */
|
|
31
30
|
|
|
32
31
|
import { UNDEFINED_VALUE, UNDEFINED_TYPE, FUNCTION_TYPE, EMPTY_UINT8_ARRAY } from "../constants.js";
|
|
33
32
|
import { encodeText } from "./../util/encode-text.js";
|
|
@@ -64,12 +63,12 @@ let createEngine = createDefaultEngine;
|
|
|
64
63
|
class AESDecryptionStream extends TransformStream {
|
|
65
64
|
|
|
66
65
|
constructor({ password, rawPassword, encryptionStrength, checkPasswordOnly, checkAuthenticationCode = true }) {
|
|
66
|
+
const aesCrypto = {};
|
|
67
67
|
super({
|
|
68
68
|
start() {
|
|
69
|
-
initAesCrypto(
|
|
69
|
+
initAesCrypto(aesCrypto, password, rawPassword, encryptionStrength);
|
|
70
70
|
},
|
|
71
71
|
async transform(chunk, controller) {
|
|
72
|
-
const aesCrypto = this;
|
|
73
72
|
const {
|
|
74
73
|
password,
|
|
75
74
|
strength,
|
|
@@ -88,6 +87,9 @@ class AESDecryptionStream extends TransformStream {
|
|
|
88
87
|
} else {
|
|
89
88
|
await ready;
|
|
90
89
|
}
|
|
90
|
+
if (aesCrypto.discarded) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
91
93
|
const output = new Uint8Array(chunk.length - AUTHENTICATION_CODE_LENGTH - ((chunk.length - AUTHENTICATION_CODE_LENGTH) % BLOCK_LENGTH));
|
|
92
94
|
controller.enqueue(append(aesCrypto, chunk, output, 0, AUTHENTICATION_CODE_LENGTH, true));
|
|
93
95
|
},
|
|
@@ -96,9 +98,12 @@ class AESDecryptionStream extends TransformStream {
|
|
|
96
98
|
engine,
|
|
97
99
|
pendingInput,
|
|
98
100
|
ready
|
|
99
|
-
} =
|
|
101
|
+
} = aesCrypto;
|
|
100
102
|
if (engine) {
|
|
101
103
|
await ready;
|
|
104
|
+
if (aesCrypto.discarded) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
102
107
|
const originalAuthenticationCode = subarray(pendingInput, pendingInput.length - AUTHENTICATION_CODE_LENGTH);
|
|
103
108
|
const decryptedChunkArray = new Uint8Array(subarray(pendingInput, 0, pendingInput.length - AUTHENTICATION_CODE_LENGTH));
|
|
104
109
|
engine.process(decryptedChunkArray, true);
|
|
@@ -108,27 +113,26 @@ class AESDecryptionStream extends TransformStream {
|
|
|
108
113
|
invalidAuthenticationCode |= authenticationCode[indexByte] ^ originalAuthenticationCode[indexByte];
|
|
109
114
|
}
|
|
110
115
|
if (invalidAuthenticationCode && checkAuthenticationCode) {
|
|
111
|
-
|
|
116
|
+
controller.error(new Error(ERR_INVALID_AUTHENTICATION_CODE));
|
|
117
|
+
return;
|
|
112
118
|
}
|
|
113
119
|
controller.enqueue(decryptedChunkArray);
|
|
114
120
|
}
|
|
115
|
-
},
|
|
116
|
-
cancel() {
|
|
117
|
-
disposeEngine(this);
|
|
118
121
|
}
|
|
119
122
|
});
|
|
123
|
+
setDisposingReadable(this, aesCrypto);
|
|
120
124
|
}
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
class AESEncryptionStream extends TransformStream {
|
|
124
128
|
|
|
125
129
|
constructor({ password, rawPassword, encryptionStrength }) {
|
|
130
|
+
const aesCrypto = {};
|
|
126
131
|
super({
|
|
127
132
|
start() {
|
|
128
|
-
initAesCrypto(
|
|
133
|
+
initAesCrypto(aesCrypto, password, rawPassword, encryptionStrength);
|
|
129
134
|
},
|
|
130
135
|
async transform(chunk, controller) {
|
|
131
|
-
const aesCrypto = this;
|
|
132
136
|
const {
|
|
133
137
|
password,
|
|
134
138
|
strength,
|
|
@@ -142,6 +146,9 @@ class AESEncryptionStream extends TransformStream {
|
|
|
142
146
|
} else {
|
|
143
147
|
await ready;
|
|
144
148
|
}
|
|
149
|
+
if (aesCrypto.discarded) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
145
152
|
const output = new Uint8Array(preamble.length + chunk.length - (chunk.length % BLOCK_LENGTH));
|
|
146
153
|
output.set(preamble, 0);
|
|
147
154
|
controller.enqueue(append(aesCrypto, chunk, output, preamble.length, 0, false));
|
|
@@ -151,19 +158,20 @@ class AESEncryptionStream extends TransformStream {
|
|
|
151
158
|
engine,
|
|
152
159
|
pendingInput,
|
|
153
160
|
ready
|
|
154
|
-
} =
|
|
161
|
+
} = aesCrypto;
|
|
155
162
|
if (engine) {
|
|
156
163
|
await ready;
|
|
164
|
+
if (aesCrypto.discarded) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
157
167
|
const encryptedChunkArray = new Uint8Array(pendingInput);
|
|
158
168
|
engine.process(encryptedChunkArray, false);
|
|
159
169
|
const authenticationCode = subarray(engine.digest(), 0, AUTHENTICATION_CODE_LENGTH);
|
|
160
170
|
controller.enqueue(concat(encryptedChunkArray, authenticationCode));
|
|
161
171
|
}
|
|
162
|
-
},
|
|
163
|
-
cancel() {
|
|
164
|
-
disposeEngine(this);
|
|
165
172
|
}
|
|
166
173
|
});
|
|
174
|
+
setDisposingReadable(this, aesCrypto);
|
|
167
175
|
}
|
|
168
176
|
}
|
|
169
177
|
|
|
@@ -182,7 +190,37 @@ function initAesCrypto(aesCrypto, password, rawPassword, encryptionStrength) {
|
|
|
182
190
|
ready: new Promise(resolve => aesCrypto.resolveReady = resolve),
|
|
183
191
|
password: encodePassword(password, rawPassword),
|
|
184
192
|
strength: encryptionStrength - 1,
|
|
185
|
-
pendingInput: EMPTY_UINT8_ARRAY
|
|
193
|
+
pendingInput: EMPTY_UINT8_ARRAY,
|
|
194
|
+
discarded: false
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function setDisposingReadable(stream, aesCrypto) {
|
|
199
|
+
const reader = stream.readable.getReader();
|
|
200
|
+
const readable = new ReadableStream({
|
|
201
|
+
async pull(controller) {
|
|
202
|
+
try {
|
|
203
|
+
const { value, done } = await reader.read();
|
|
204
|
+
if (done) {
|
|
205
|
+
controller.close();
|
|
206
|
+
} else {
|
|
207
|
+
controller.enqueue(value);
|
|
208
|
+
}
|
|
209
|
+
} catch (error) {
|
|
210
|
+
disposeEngine(aesCrypto);
|
|
211
|
+
reader.cancel(error).catch(() => { });
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
cancel(reason) {
|
|
216
|
+
disposeEngine(aesCrypto);
|
|
217
|
+
return reader.cancel(reason);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
Object.defineProperty(stream, "readable", {
|
|
221
|
+
get() {
|
|
222
|
+
return readable;
|
|
223
|
+
}
|
|
186
224
|
});
|
|
187
225
|
}
|
|
188
226
|
|
|
@@ -215,7 +253,9 @@ async function createDecryptionKeys(decrypt, strength, password, preamble) {
|
|
|
215
253
|
}
|
|
216
254
|
}
|
|
217
255
|
|
|
218
|
-
function disposeEngine(
|
|
256
|
+
function disposeEngine(aesCrypto) {
|
|
257
|
+
const { engine } = aesCrypto;
|
|
258
|
+
aesCrypto.discarded = true;
|
|
219
259
|
if (engine && engine.dispose) {
|
|
220
260
|
engine.dispose();
|
|
221
261
|
}
|
|
@@ -232,6 +272,9 @@ async function createKeys(aesCrypto, strength, password, salt) {
|
|
|
232
272
|
const keyLength = KEY_LENGTH[strength];
|
|
233
273
|
const compositeKey = await deriveKey(password, salt, keyLength * 2 + PASSWORD_VERIFICATION_LENGTH);
|
|
234
274
|
aesCrypto.engine = createEngine(subarray(compositeKey, 0, keyLength), subarray(compositeKey, keyLength, keyLength * 2));
|
|
275
|
+
if (aesCrypto.discarded) {
|
|
276
|
+
disposeEngine(aesCrypto);
|
|
277
|
+
}
|
|
235
278
|
return subarray(compositeKey, keyLength * 2);
|
|
236
279
|
}
|
|
237
280
|
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
ERR_INVALID_AUTHENTICATION_CODE,
|
|
44
44
|
ERR_INVALID_UNCOMPRESSED_SIZE,
|
|
45
45
|
ERR_INVALID_COMPRESSED_DATA,
|
|
46
|
+
ERR_CODEC_OUT_OF_MEMORY,
|
|
46
47
|
ERR_ABORT_CHECK_PASSWORD,
|
|
47
48
|
ERR_UNSUPPORTED_CRYPTO_API,
|
|
48
49
|
InflateStream,
|
|
@@ -77,6 +78,7 @@ export {
|
|
|
77
78
|
ERR_INVALID_AUTHENTICATION_CODE,
|
|
78
79
|
ERR_INVALID_UNCOMPRESSED_SIZE,
|
|
79
80
|
ERR_INVALID_COMPRESSED_DATA,
|
|
81
|
+
ERR_CODEC_OUT_OF_MEMORY,
|
|
80
82
|
ERR_ABORT_CHECK_PASSWORD,
|
|
81
83
|
ERR_UNSUPPORTED_CRYPTO_API,
|
|
82
84
|
CodecStream,
|
|
@@ -127,11 +127,11 @@ function encrypt(target, input) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function createKeys(target, password, rawPassword) {
|
|
130
|
-
const
|
|
130
|
+
const cryptoKeys = [0x12345678, 0x23456789, 0x34567890];
|
|
131
131
|
Object.assign(target, {
|
|
132
|
-
|
|
133
|
-
crcKey0: new Crc32(
|
|
134
|
-
crcKey2: new Crc32(
|
|
132
|
+
cryptoKeys,
|
|
133
|
+
crcKey0: new Crc32(cryptoKeys[0]),
|
|
134
|
+
crcKey2: new Crc32(cryptoKeys[2])
|
|
135
135
|
});
|
|
136
136
|
if (rawPassword) {
|
|
137
137
|
for (let index = 0; index < rawPassword.length; index++) {
|
|
@@ -145,17 +145,17 @@ function createKeys(target, password, rawPassword) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
function updateKeys(target, byte) {
|
|
148
|
-
let [, key1] = target.
|
|
148
|
+
let [, key1] = target.cryptoKeys;
|
|
149
149
|
target.crcKey0.append([byte]);
|
|
150
150
|
const key0 = ~target.crcKey0.get();
|
|
151
151
|
key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
|
|
152
152
|
target.crcKey2.append([key1 >>> 24]);
|
|
153
153
|
const key2 = ~target.crcKey2.get();
|
|
154
|
-
target.
|
|
154
|
+
target.cryptoKeys = [key0, key1, key2];
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
function getByte(target) {
|
|
158
|
-
const temp = target.
|
|
158
|
+
const temp = target.cryptoKeys[2] | 2;
|
|
159
159
|
return getInt8(Math.imul(temp, (temp ^ 1)) >>> 8);
|
|
160
160
|
}
|
|
161
161
|
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global TransformStream, ReadableStream
|
|
29
|
+
/* global TransformStream, ReadableStream */
|
|
30
30
|
// deno-lint-ignore-file no-this-alias
|
|
31
31
|
|
|
32
32
|
import { Crc32 } from "./codecs/crc32.js";
|
|
@@ -48,11 +48,14 @@ import {
|
|
|
48
48
|
import { UNDEFINED_VALUE } from "../constants.js";
|
|
49
49
|
import { concat, getDataView } from "../util/array.js";
|
|
50
50
|
import { toCompatibleReadable } from "../util/compatible-streams.js";
|
|
51
|
+
import { isErrorObject } from "../util/error.js";
|
|
51
52
|
import { getCodecStreams, ERR_UNSUPPORTED_COMPRESSION } from "../codec-registry.js";
|
|
52
53
|
|
|
53
54
|
const ERR_INVALID_UNCOMPRESSED_SIZE = "Invalid uncompressed size";
|
|
54
55
|
const ERR_INVALID_COMPRESSED_DATA = "Invalid compressed data";
|
|
56
|
+
const ERR_CODEC_OUT_OF_MEMORY = "Codec out of memory";
|
|
55
57
|
const ERR_INVALID_CRC32 = "Invalid CRC32";
|
|
58
|
+
const Z_MEM_ERROR_CODE = "Z_MEM_ERROR";
|
|
56
59
|
const FORMAT_DEFLATE_RAW = "deflate-raw";
|
|
57
60
|
const FORMAT_DEFLATE64_RAW = "deflate64-raw";
|
|
58
61
|
const FORMAT_GZIP = "gzip";
|
|
@@ -87,13 +90,13 @@ class DeflateStream extends TransformStream {
|
|
|
87
90
|
readable = pipeThroughCompressionStream(readable, useCompressionStream, { level, chunkSize }, CompressionStream, CompressionStreamFallback);
|
|
88
91
|
} catch (error) {
|
|
89
92
|
if (!useCompressionStream && CompressionStreamFallback) {
|
|
90
|
-
throw error;
|
|
93
|
+
throw mapMemoryError(error);
|
|
91
94
|
}
|
|
92
95
|
let gzipStream;
|
|
93
96
|
try {
|
|
94
97
|
gzipStream = new CompressionStream(FORMAT_GZIP);
|
|
95
98
|
} catch {
|
|
96
|
-
throw error;
|
|
99
|
+
throw mapMemoryError(error);
|
|
97
100
|
}
|
|
98
101
|
readable = pipeThroughBackpressured(readable, gzipStream);
|
|
99
102
|
readable = pipeThrough(readable, new GzipToRawDeflateStream());
|
|
@@ -157,53 +160,30 @@ class GzipToRawDeflateStream extends TransformStream {
|
|
|
157
160
|
}
|
|
158
161
|
}
|
|
159
162
|
|
|
160
|
-
function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32) {
|
|
163
|
+
function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors) {
|
|
161
164
|
const writer = gzipStream.writable.getWriter();
|
|
162
165
|
const reader = gzipStream.readable.getReader();
|
|
163
166
|
const outputCrc32 = crc32 === UNDEFINED_VALUE ? new Crc32() : UNDEFINED_VALUE;
|
|
164
167
|
let outputLength = 0;
|
|
165
|
-
let inputDone = false;
|
|
166
168
|
let trailerWritten = false;
|
|
167
|
-
let
|
|
168
|
-
let
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
trailerReady.catch(() => { });
|
|
176
|
-
pump();
|
|
177
|
-
return new ReadableStream({
|
|
178
|
-
async pull(controller) {
|
|
179
|
-
let result;
|
|
180
|
-
try {
|
|
181
|
-
result = await read();
|
|
182
|
-
} catch (error) {
|
|
183
|
-
throw trailerWritten ? getTrailerError(error) : error;
|
|
184
|
-
}
|
|
185
|
-
const { value, done } = result;
|
|
186
|
-
if (done) {
|
|
187
|
-
controller.close();
|
|
188
|
-
} else {
|
|
189
|
-
outputLength += value.length;
|
|
190
|
-
if (outputLength > outputSize) {
|
|
191
|
-
const error = new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
192
|
-
rejectTrailerReady(error);
|
|
193
|
-
await cancel(reader, error);
|
|
194
|
-
throw error;
|
|
195
|
-
}
|
|
196
|
-
if (outputCrc32) {
|
|
197
|
-
outputCrc32.append(value);
|
|
198
|
-
}
|
|
199
|
-
controller.enqueue(value);
|
|
200
|
-
}
|
|
169
|
+
let settled = false;
|
|
170
|
+
let resolvePull, controller;
|
|
171
|
+
const output = new ReadableStream({
|
|
172
|
+
start(streamController) {
|
|
173
|
+
controller = streamController;
|
|
174
|
+
},
|
|
175
|
+
pull() {
|
|
176
|
+
resumePump();
|
|
201
177
|
},
|
|
202
178
|
cancel(reason) {
|
|
203
|
-
|
|
179
|
+
settled = true;
|
|
180
|
+
resumePump();
|
|
204
181
|
return reader.cancel(reason);
|
|
205
182
|
}
|
|
206
183
|
});
|
|
184
|
+
pump();
|
|
185
|
+
drain();
|
|
186
|
+
return output;
|
|
207
187
|
|
|
208
188
|
async function pump() {
|
|
209
189
|
const inputReader = readable.getReader();
|
|
@@ -212,19 +192,16 @@ function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, cr
|
|
|
212
192
|
header.set(GZIP_HEADER_BYTES);
|
|
213
193
|
await writer.write(header);
|
|
214
194
|
for (; ;) {
|
|
195
|
+
await outputCapacity();
|
|
215
196
|
await writer.ready;
|
|
216
|
-
const { value, done } = await inputReader
|
|
197
|
+
const { value, done } = await readSource(inputReader, sourceErrors);
|
|
217
198
|
if (done) {
|
|
218
199
|
break;
|
|
219
200
|
}
|
|
220
201
|
await writer.write(value);
|
|
221
202
|
}
|
|
222
|
-
inputDone = true;
|
|
223
203
|
if (outputCrc32) {
|
|
224
|
-
|
|
225
|
-
armIdleCheck();
|
|
226
|
-
}
|
|
227
|
-
await trailerReady;
|
|
204
|
+
await writer.write(new Uint8Array(0));
|
|
228
205
|
}
|
|
229
206
|
const trailer = new Uint8Array(GZIP_TRAILER_LENGTH);
|
|
230
207
|
const dataView = getDataView(trailer);
|
|
@@ -239,54 +216,68 @@ function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, cr
|
|
|
239
216
|
}
|
|
240
217
|
}
|
|
241
218
|
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
219
|
+
async function drain() {
|
|
220
|
+
try {
|
|
221
|
+
for (; ;) {
|
|
222
|
+
const { value, done } = await read();
|
|
223
|
+
if (done) {
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
outputLength += value.length;
|
|
227
|
+
if (outputLength > outputSize) {
|
|
228
|
+
throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
229
|
+
}
|
|
230
|
+
if (outputCrc32) {
|
|
231
|
+
outputCrc32.append(value);
|
|
232
|
+
}
|
|
233
|
+
controller.enqueue(value);
|
|
234
|
+
}
|
|
235
|
+
if (!settled) {
|
|
236
|
+
settled = true;
|
|
237
|
+
controller.close();
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
fail(error);
|
|
241
|
+
await cancel(reader, error);
|
|
249
242
|
}
|
|
250
|
-
return result;
|
|
251
243
|
}
|
|
252
244
|
|
|
253
|
-
function
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
await nextTask();
|
|
262
|
-
idleCheckArmed = false;
|
|
263
|
-
if (readPending) {
|
|
264
|
-
if (readCount == count) {
|
|
265
|
-
resolveTrailerReady();
|
|
266
|
-
} else {
|
|
267
|
-
armIdleCheck();
|
|
245
|
+
function read() {
|
|
246
|
+
return reader.read().catch(error => {
|
|
247
|
+
if (trailerWritten) {
|
|
248
|
+
if (!outputCrc32) {
|
|
249
|
+
throw mapError(error, ERR_INVALID_CRC32);
|
|
250
|
+
}
|
|
251
|
+
if (outputLength != outputSize) {
|
|
252
|
+
throw mapError(error, ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
268
253
|
}
|
|
254
|
+
return { done: true };
|
|
269
255
|
}
|
|
270
|
-
|
|
256
|
+
throw mapCodecError(error, sourceErrors);
|
|
257
|
+
});
|
|
271
258
|
}
|
|
272
259
|
|
|
273
|
-
function
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
260
|
+
function outputCapacity() {
|
|
261
|
+
if (!settled && controller.desiredSize <= 0) {
|
|
262
|
+
return new Promise(resolve => resolvePull = resolve);
|
|
263
|
+
}
|
|
277
264
|
}
|
|
278
|
-
}
|
|
279
265
|
|
|
280
|
-
function
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
port1.close();
|
|
285
|
-
port2.close();
|
|
266
|
+
function resumePump() {
|
|
267
|
+
if (resolvePull) {
|
|
268
|
+
const resolve = resolvePull;
|
|
269
|
+
resolvePull = UNDEFINED_VALUE;
|
|
286
270
|
resolve();
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function fail(error) {
|
|
275
|
+
if (!settled) {
|
|
276
|
+
settled = true;
|
|
277
|
+
controller.error(error);
|
|
278
|
+
resumePump();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
290
281
|
}
|
|
291
282
|
|
|
292
283
|
class InflateStream extends TransformStream {
|
|
@@ -305,11 +296,12 @@ class InflateStream extends TransformStream {
|
|
|
305
296
|
}
|
|
306
297
|
}
|
|
307
298
|
if (compressed) {
|
|
299
|
+
const sourceErrors = new Set();
|
|
308
300
|
const codecStreams = format && getCodecStreams(format);
|
|
301
|
+
let gzipStream;
|
|
309
302
|
if (codecStreams) {
|
|
310
|
-
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }));
|
|
303
|
+
readable = pipeThroughBackpressured(readable, createCodecStream(codecStreams.DecompressionStream, format, { chunkSize, compressionMethod, rawBitFlag, uncompressedSize: outputSize }), sourceErrors);
|
|
311
304
|
} else {
|
|
312
|
-
let gzipStream;
|
|
313
305
|
const GzipDecompressionStream = getGzipCodecStream(useCompressionStream, DecompressionStream, DecompressionStreamFallback);
|
|
314
306
|
if (checkCrc32 && !deflate64 && crc32 !== UNDEFINED_VALUE && outputSize !== UNDEFINED_VALUE && GzipDecompressionStream) {
|
|
315
307
|
try {
|
|
@@ -320,24 +312,25 @@ class InflateStream extends TransformStream {
|
|
|
320
312
|
}
|
|
321
313
|
if (!gzipStream) {
|
|
322
314
|
try {
|
|
323
|
-
readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback);
|
|
315
|
+
readable = pipeThroughCompressionStream(readable, useCompressionStream, { chunkSize, deflate64 }, DecompressionStream, DecompressionStreamFallback, sourceErrors);
|
|
324
316
|
} catch (error) {
|
|
325
317
|
if (deflate64 || outputSize === UNDEFINED_VALUE || (!useCompressionStream && DecompressionStreamFallback)) {
|
|
326
|
-
throw error;
|
|
318
|
+
throw mapMemoryError(error);
|
|
327
319
|
}
|
|
328
320
|
try {
|
|
329
321
|
gzipStream = new DecompressionStream(FORMAT_GZIP);
|
|
330
322
|
} catch {
|
|
331
|
-
throw error;
|
|
323
|
+
throw mapMemoryError(error);
|
|
332
324
|
}
|
|
333
325
|
}
|
|
334
326
|
}
|
|
335
|
-
if (gzipStream) {
|
|
336
|
-
gzipCrc32 = true;
|
|
337
|
-
readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32);
|
|
338
|
-
}
|
|
339
327
|
}
|
|
340
|
-
|
|
328
|
+
if (gzipStream) {
|
|
329
|
+
gzipCrc32 = true;
|
|
330
|
+
readable = pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, crc32, sourceErrors);
|
|
331
|
+
} else {
|
|
332
|
+
readable = mapInflateStreamError(readable, sourceErrors);
|
|
333
|
+
}
|
|
341
334
|
}
|
|
342
335
|
if (checkCrc32 && !gzipCrc32) {
|
|
343
336
|
crc32Stream = new Crc32Stream();
|
|
@@ -400,6 +393,7 @@ export {
|
|
|
400
393
|
ERR_INVALID_AUTHENTICATION_CODE,
|
|
401
394
|
ERR_INVALID_UNCOMPRESSED_SIZE,
|
|
402
395
|
ERR_INVALID_COMPRESSED_DATA,
|
|
396
|
+
ERR_CODEC_OUT_OF_MEMORY,
|
|
403
397
|
ERR_ABORT_CHECK_PASSWORD,
|
|
404
398
|
ERR_UNSUPPORTED_CRYPTO_API
|
|
405
399
|
};
|
|
@@ -428,7 +422,7 @@ function getGzipCodecStream(useCompressionStream, CodecStreamNative, CodecStream
|
|
|
428
422
|
}
|
|
429
423
|
}
|
|
430
424
|
|
|
431
|
-
function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback) {
|
|
425
|
+
function pipeThroughCompressionStream(readable, useCompressionStream, options, CompressionStreamNative, CompressionStreamFallback, sourceErrors) {
|
|
432
426
|
const Stream = useCompressionStream && CompressionStreamNative ?
|
|
433
427
|
CompressionStreamNative :
|
|
434
428
|
CompressionStreamFallback || CompressionStreamNative;
|
|
@@ -443,14 +437,14 @@ function pipeThroughCompressionStream(readable, useCompressionStream, options, C
|
|
|
443
437
|
throw error;
|
|
444
438
|
}
|
|
445
439
|
}
|
|
446
|
-
return pipeThroughBackpressured(readable, codecStream);
|
|
440
|
+
return pipeThroughBackpressured(readable, codecStream, sourceErrors);
|
|
447
441
|
}
|
|
448
442
|
|
|
449
443
|
function pipeThrough(readable, transformStream) {
|
|
450
444
|
return toCompatibleReadable(readable).pipeThrough(transformStream);
|
|
451
445
|
}
|
|
452
446
|
|
|
453
|
-
function pipeThroughBackpressured(readable, transformStream) {
|
|
447
|
+
function pipeThroughBackpressured(readable, transformStream, sourceErrors) {
|
|
454
448
|
const writer = transformStream.writable.getWriter();
|
|
455
449
|
const reader = readable.getReader();
|
|
456
450
|
pump();
|
|
@@ -460,7 +454,7 @@ function pipeThroughBackpressured(readable, transformStream) {
|
|
|
460
454
|
try {
|
|
461
455
|
for (; ;) {
|
|
462
456
|
await writer.ready;
|
|
463
|
-
const result = await reader
|
|
457
|
+
const result = await readSource(reader, sourceErrors);
|
|
464
458
|
if (result.done) {
|
|
465
459
|
await writer.close();
|
|
466
460
|
break;
|
|
@@ -490,26 +484,49 @@ async function cancel(reader, error) {
|
|
|
490
484
|
}
|
|
491
485
|
}
|
|
492
486
|
|
|
493
|
-
function
|
|
487
|
+
function readSource(reader, sourceErrors) {
|
|
488
|
+
const result = reader.read();
|
|
489
|
+
return sourceErrors ? result.catch(error => {
|
|
490
|
+
sourceErrors.add(error);
|
|
491
|
+
throw error;
|
|
492
|
+
}) : result;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function mapCodecError(error, sourceErrors) {
|
|
496
|
+
if (sourceErrors.has(error)) {
|
|
497
|
+
return error;
|
|
498
|
+
}
|
|
499
|
+
return mapError(error, isMemoryError(error) ? ERR_CODEC_OUT_OF_MEMORY : ERR_INVALID_COMPRESSED_DATA);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function mapMemoryError(error) {
|
|
503
|
+
return isMemoryError(error) ? mapError(error, ERR_CODEC_OUT_OF_MEMORY) : error;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function isMemoryError(error) {
|
|
507
|
+
return isErrorObject(error) && error.code == Z_MEM_ERROR_CODE;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function mapError(error, message) {
|
|
511
|
+
const mappedError = new Error(message);
|
|
512
|
+
mappedError.cause = error;
|
|
513
|
+
return mappedError;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function mapInflateStreamError(readable, sourceErrors) {
|
|
494
517
|
const reader = readable.getReader();
|
|
495
518
|
return new ReadableStream({
|
|
496
519
|
async pull(controller) {
|
|
497
|
-
let result;
|
|
498
520
|
try {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
521
|
+
const { value, done } = await reader.read();
|
|
522
|
+
if (done) {
|
|
523
|
+
controller.close();
|
|
524
|
+
} else {
|
|
525
|
+
controller.enqueue(value);
|
|
503
526
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
throw
|
|
507
|
-
}
|
|
508
|
-
const { value, done } = result;
|
|
509
|
-
if (done) {
|
|
510
|
-
controller.close();
|
|
511
|
-
} else {
|
|
512
|
-
controller.enqueue(value);
|
|
527
|
+
} catch (error) {
|
|
528
|
+
await cancel(reader, error);
|
|
529
|
+
throw mapCodecError(error, sourceErrors);
|
|
513
530
|
}
|
|
514
531
|
},
|
|
515
532
|
cancel(reason) {
|