@zip.js/zip.js 2.16.0 → 2.16.1
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 +284 -179
- package/dist/zip-core-external.min.js +1 -1
- package/dist/zip-core.js +108 -61
- package/dist/zip-core.min.js +1 -1
- package/dist/zip-fs-core-external.js +426 -189
- package/dist/zip-fs-core-external.min.js +1 -1
- package/dist/zip-fs-core.js +251 -70
- package/dist/zip-fs-core.min.js +1 -1
- package/dist/zip-fs-external.js +426 -189
- package/dist/zip-fs-external.min.js +1 -1
- package/dist/zip-fs-native.js +253 -72
- package/dist/zip-fs-native.min.js +1 -1
- package/dist/zip-fs.js +428 -189
- package/dist/zip-fs.min.js +1 -1
- package/dist/zip-legacy.js +110 -63
- package/dist/zip-legacy.min.js +1 -1
- package/dist/zip-native.js +110 -63
- 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 +285 -180
- package/dist/zip.min.js +1 -1
- package/eslint.config.mjs +1 -1
- package/index-native.cjs +253 -72
- package/index-native.min.js +1 -1
- package/index.cjs +428 -189
- package/index.d.cts +117 -16
- package/index.d.ts +117 -16
- package/index.min.js +1 -1
- package/lib/core/streams/aes-crypto-stream.js +60 -17
- package/lib/core/streams/zip-crypto-stream.js +7 -7
- package/lib/core/streams/zip-entry-stream.js +22 -26
- package/lib/core/streams/zlib-wasm/zlib-streams.js +176 -118
- package/lib/core/util/compatible-streams.js +10 -5
- package/lib/core/version.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 +144 -10
- package/lib/core/zip-reader.js +5 -5
- package/lib/core/zip-writer.js +4 -2
- package/package.json +3 -2
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -176,28 +176,25 @@ function pipeThroughGzipDecompressionStream(readable, gzipStream, outputSize, cr
|
|
|
176
176
|
pump();
|
|
177
177
|
return new ReadableStream({
|
|
178
178
|
async pull(controller) {
|
|
179
|
-
let result;
|
|
180
179
|
try {
|
|
181
|
-
|
|
180
|
+
const { value, done } = await read();
|
|
181
|
+
if (done) {
|
|
182
|
+
controller.close();
|
|
183
|
+
} else {
|
|
184
|
+
outputLength += value.length;
|
|
185
|
+
if (outputLength > outputSize) {
|
|
186
|
+
throw new Error(ERR_INVALID_UNCOMPRESSED_SIZE);
|
|
187
|
+
}
|
|
188
|
+
if (outputCrc32) {
|
|
189
|
+
outputCrc32.append(value);
|
|
190
|
+
}
|
|
191
|
+
controller.enqueue(value);
|
|
192
|
+
}
|
|
182
193
|
} catch (error) {
|
|
194
|
+
rejectTrailerReady(error);
|
|
195
|
+
await cancel(reader, error);
|
|
183
196
|
throw trailerWritten ? getTrailerError(error) : error;
|
|
184
197
|
}
|
|
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
|
-
}
|
|
201
198
|
},
|
|
202
199
|
cancel(reason) {
|
|
203
200
|
rejectTrailerReady(reason);
|
|
@@ -494,10 +491,15 @@ function mapInflateStreamError(readable) {
|
|
|
494
491
|
const reader = readable.getReader();
|
|
495
492
|
return new ReadableStream({
|
|
496
493
|
async pull(controller) {
|
|
497
|
-
let result;
|
|
498
494
|
try {
|
|
499
|
-
|
|
495
|
+
const { value, done } = await reader.read();
|
|
496
|
+
if (done) {
|
|
497
|
+
controller.close();
|
|
498
|
+
} else {
|
|
499
|
+
controller.enqueue(value);
|
|
500
|
+
}
|
|
500
501
|
} catch (error) {
|
|
502
|
+
await cancel(reader, error);
|
|
501
503
|
if (error && error.message) {
|
|
502
504
|
throw error;
|
|
503
505
|
}
|
|
@@ -505,12 +507,6 @@ function mapInflateStreamError(readable) {
|
|
|
505
507
|
mappedError.cause = error;
|
|
506
508
|
throw mappedError;
|
|
507
509
|
}
|
|
508
|
-
const { value, done } = result;
|
|
509
|
-
if (done) {
|
|
510
|
-
controller.close();
|
|
511
|
-
} else {
|
|
512
|
-
controller.enqueue(value);
|
|
513
|
-
}
|
|
514
510
|
},
|
|
515
511
|
cancel(reason) {
|
|
516
512
|
return reader.cancel(reason);
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
/* global
|
|
29
|
+
/* global ReadableStream, WritableStream */
|
|
30
30
|
|
|
31
31
|
const FORMAT_DEFLATE = "deflate";
|
|
32
32
|
const FORMAT_DEFLATE_RAW = "deflate-raw";
|
|
@@ -61,137 +61,195 @@ function _make(isCompress, type, options = {}) {
|
|
|
61
61
|
const level = (typeof options.level === "number") ? options.level : -1;
|
|
62
62
|
const outBufferSize = (typeof options.outBuffer === "number") ? options.outBuffer : 64 * 1024;
|
|
63
63
|
const inBufferSize = (typeof options.inBufferSize === "number") ? options.inBufferSize : 64 * 1024;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const state = { out: 0, in: 0, inBufferSize: 0, streamHandle: 0 };
|
|
65
|
+
let readableController, writableController, resolveWrite, cancelReason;
|
|
66
|
+
let backpressure = true;
|
|
67
|
+
let cancelled = false;
|
|
68
|
+
initStream();
|
|
69
|
+
const readable = new ReadableStream({
|
|
70
|
+
start(controller) {
|
|
71
|
+
readableController = controller;
|
|
72
|
+
},
|
|
73
|
+
pull() {
|
|
74
|
+
backpressure = false;
|
|
75
|
+
resumeWrite();
|
|
76
|
+
},
|
|
77
|
+
cancel(reason) {
|
|
78
|
+
cancelled = true;
|
|
79
|
+
cancelReason = reason;
|
|
80
|
+
disposeStream(state);
|
|
81
|
+
writableController.error(reason);
|
|
82
|
+
resumeWrite();
|
|
83
|
+
}
|
|
84
|
+
}, { highWaterMark: 0 });
|
|
85
|
+
const writable = new WritableStream({
|
|
86
|
+
start(controller) {
|
|
87
|
+
writableController = controller;
|
|
88
|
+
},
|
|
89
|
+
async write(chunk) {
|
|
90
|
+
if (backpressure) {
|
|
91
|
+
await new Promise(resolve => resolveWrite = resolve);
|
|
92
|
+
}
|
|
93
|
+
if (cancelled) {
|
|
94
|
+
throw cancelReason;
|
|
95
|
+
}
|
|
67
96
|
try {
|
|
68
|
-
|
|
69
|
-
this.out = malloc(outBufferSize);
|
|
70
|
-
this.in = malloc(inBufferSize);
|
|
71
|
-
this.inBufferSize = inBufferSize;
|
|
72
|
-
if (!this.out || !this.in) {
|
|
73
|
-
throw new Error("allocation failed");
|
|
74
|
-
}
|
|
75
|
-
if (isCompress) {
|
|
76
|
-
this._process = wasm.deflate_process;
|
|
77
|
-
this._last_consumed = wasm.deflate_last_consumed;
|
|
78
|
-
this._end = wasm.deflate_end;
|
|
79
|
-
this.streamHandle = wasm.deflate_new();
|
|
80
|
-
if (type === FORMAT_GZIP) {
|
|
81
|
-
result = wasm.deflate_init_gzip(this.streamHandle, level);
|
|
82
|
-
} else if (type === FORMAT_DEFLATE_RAW) {
|
|
83
|
-
result = wasm.deflate_init_raw(this.streamHandle, level);
|
|
84
|
-
} else {
|
|
85
|
-
result = wasm.deflate_init(this.streamHandle, level);
|
|
86
|
-
}
|
|
87
|
-
} else {
|
|
88
|
-
if (type === FORMAT_DEFLATE64_RAW) {
|
|
89
|
-
this._process = wasm.inflate9_process;
|
|
90
|
-
this._last_consumed = wasm.inflate9_last_consumed;
|
|
91
|
-
this._end = wasm.inflate9_end;
|
|
92
|
-
this.streamHandle = wasm.inflate9_new();
|
|
93
|
-
result = wasm.inflate9_init_raw(this.streamHandle);
|
|
94
|
-
} else {
|
|
95
|
-
this._process = wasm.inflate_process;
|
|
96
|
-
this._last_consumed = wasm.inflate_last_consumed;
|
|
97
|
-
this._end = wasm.inflate_end;
|
|
98
|
-
this.streamHandle = wasm.inflate_new();
|
|
99
|
-
if (type === FORMAT_DEFLATE_RAW) {
|
|
100
|
-
result = wasm.inflate_init_raw(this.streamHandle);
|
|
101
|
-
} else if (type === FORMAT_GZIP) {
|
|
102
|
-
result = wasm.inflate_init_gzip(this.streamHandle);
|
|
103
|
-
} else {
|
|
104
|
-
result = wasm.inflate_init(this.streamHandle);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (result !== 0) {
|
|
109
|
-
throw new Error("init failed:" + result);
|
|
110
|
-
}
|
|
97
|
+
processChunk(chunk);
|
|
111
98
|
} catch (error) {
|
|
112
|
-
disposeStream(
|
|
99
|
+
disposeStream(state);
|
|
100
|
+
readableController.error(error);
|
|
113
101
|
throw error;
|
|
114
102
|
}
|
|
115
103
|
},
|
|
116
|
-
|
|
104
|
+
close() {
|
|
105
|
+
if (cancelled) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
117
108
|
try {
|
|
118
|
-
|
|
119
|
-
const heap = new Uint8Array(memory.buffer);
|
|
120
|
-
const process = this._process;
|
|
121
|
-
const last_consumed = this._last_consumed;
|
|
122
|
-
const out = this.out;
|
|
123
|
-
let offset = 0;
|
|
124
|
-
while (offset < buffer.length) {
|
|
125
|
-
const toRead = Math.min(buffer.length - offset, 32 * 1024);
|
|
126
|
-
if (!this.in || this.inBufferSize < toRead) {
|
|
127
|
-
if (this.in && free) {
|
|
128
|
-
free(this.in);
|
|
129
|
-
this.in = 0;
|
|
130
|
-
}
|
|
131
|
-
this.in = malloc(toRead);
|
|
132
|
-
this.inBufferSize = toRead;
|
|
133
|
-
if (!this.in) {
|
|
134
|
-
throw new Error("allocation failed");
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
heap.set(buffer.subarray(offset, offset + toRead), this.in);
|
|
138
|
-
const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
|
|
139
|
-
// checked before the byte count is used, so a status code can never be read as one
|
|
140
|
-
const code = (result >> 24) & 0xff;
|
|
141
|
-
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
142
|
-
if (signedCode < 0) {
|
|
143
|
-
throw new Error("process error:" + signedCode);
|
|
144
|
-
}
|
|
145
|
-
const prod = result & 0x00ffffff;
|
|
146
|
-
if (prod) {
|
|
147
|
-
controller.enqueue(heap.slice(out, out + prod));
|
|
148
|
-
}
|
|
149
|
-
const consumed = last_consumed(this.streamHandle);
|
|
150
|
-
if (consumed === 0 && prod === 0) {
|
|
151
|
-
break;
|
|
152
|
-
}
|
|
153
|
-
offset += consumed;
|
|
154
|
-
}
|
|
109
|
+
flushStream();
|
|
155
110
|
} catch (error) {
|
|
156
|
-
disposeStream(
|
|
157
|
-
|
|
111
|
+
disposeStream(state);
|
|
112
|
+
readableController.error(error);
|
|
113
|
+
throw error;
|
|
158
114
|
}
|
|
115
|
+
const result = disposeStream(state);
|
|
116
|
+
if (result !== 0) {
|
|
117
|
+
const error = new Error("end error:" + result);
|
|
118
|
+
readableController.error(error);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
readableController.close();
|
|
159
122
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
123
|
+
abort(reason) {
|
|
124
|
+
disposeStream(state);
|
|
125
|
+
readableController.error(reason);
|
|
126
|
+
}
|
|
127
|
+
}, { highWaterMark: 1 });
|
|
128
|
+
return { readable, writable };
|
|
129
|
+
|
|
130
|
+
function initStream() {
|
|
131
|
+
try {
|
|
132
|
+
let result;
|
|
133
|
+
state.out = malloc(outBufferSize);
|
|
134
|
+
state.in = malloc(inBufferSize);
|
|
135
|
+
state.inBufferSize = inBufferSize;
|
|
136
|
+
if (!state.out || !state.in) {
|
|
137
|
+
throw new Error("allocation failed");
|
|
138
|
+
}
|
|
139
|
+
if (isCompress) {
|
|
140
|
+
state._process = wasm.deflate_process;
|
|
141
|
+
state._last_consumed = wasm.deflate_last_consumed;
|
|
142
|
+
state._end = wasm.deflate_end;
|
|
143
|
+
state.streamHandle = wasm.deflate_new();
|
|
144
|
+
if (type === FORMAT_GZIP) {
|
|
145
|
+
result = wasm.deflate_init_gzip(state.streamHandle, level);
|
|
146
|
+
} else if (type === FORMAT_DEFLATE_RAW) {
|
|
147
|
+
result = wasm.deflate_init_raw(state.streamHandle, level);
|
|
148
|
+
} else {
|
|
149
|
+
result = wasm.deflate_init(state.streamHandle, level);
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
if (type === FORMAT_DEFLATE64_RAW) {
|
|
153
|
+
state._process = wasm.inflate9_process;
|
|
154
|
+
state._last_consumed = wasm.inflate9_last_consumed;
|
|
155
|
+
state._end = wasm.inflate9_end;
|
|
156
|
+
state.streamHandle = wasm.inflate9_new();
|
|
157
|
+
result = wasm.inflate9_init_raw(state.streamHandle);
|
|
158
|
+
} else {
|
|
159
|
+
state._process = wasm.inflate_process;
|
|
160
|
+
state._last_consumed = wasm.inflate_last_consumed;
|
|
161
|
+
state._end = wasm.inflate_end;
|
|
162
|
+
state.streamHandle = wasm.inflate_new();
|
|
163
|
+
if (type === FORMAT_DEFLATE_RAW) {
|
|
164
|
+
result = wasm.inflate_init_raw(state.streamHandle);
|
|
165
|
+
} else if (type === FORMAT_GZIP) {
|
|
166
|
+
result = wasm.inflate_init_gzip(state.streamHandle);
|
|
167
|
+
} else {
|
|
168
|
+
result = wasm.inflate_init(state.streamHandle);
|
|
178
169
|
}
|
|
179
170
|
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
171
|
+
}
|
|
172
|
+
if (result !== 0) {
|
|
173
|
+
throw new Error("init failed:" + result);
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
disposeStream(state);
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function processChunk(chunk) {
|
|
182
|
+
const heap = new Uint8Array(memory.buffer);
|
|
183
|
+
const process = state._process;
|
|
184
|
+
const last_consumed = state._last_consumed;
|
|
185
|
+
const out = state.out;
|
|
186
|
+
let offset = 0;
|
|
187
|
+
while (offset < chunk.length) {
|
|
188
|
+
const toRead = Math.min(chunk.length - offset, 32 * 1024);
|
|
189
|
+
if (!state.in || state.inBufferSize < toRead) {
|
|
190
|
+
if (state.in && free) {
|
|
191
|
+
free(state.in);
|
|
192
|
+
state.in = 0;
|
|
193
|
+
}
|
|
194
|
+
state.in = malloc(toRead);
|
|
195
|
+
state.inBufferSize = toRead;
|
|
196
|
+
if (!state.in) {
|
|
197
|
+
throw new Error("allocation failed");
|
|
186
198
|
}
|
|
187
199
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
200
|
+
heap.set(chunk.subarray(offset, offset + toRead), state.in);
|
|
201
|
+
const result = process(state.streamHandle, state.in, toRead, out, outBufferSize, 0);
|
|
202
|
+
// checked before the byte count is used, so a status code can never be read as one
|
|
203
|
+
const code = (result >> 24) & 0xff;
|
|
204
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
205
|
+
if (signedCode < 0) {
|
|
206
|
+
throw new Error("process error:" + signedCode);
|
|
207
|
+
}
|
|
208
|
+
const prod = result & 0x00ffffff;
|
|
209
|
+
if (prod) {
|
|
210
|
+
enqueue(heap.slice(out, out + prod));
|
|
211
|
+
}
|
|
212
|
+
const consumed = last_consumed(state.streamHandle);
|
|
213
|
+
if (consumed === 0 && prod === 0) {
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
offset += consumed;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function flushStream() {
|
|
221
|
+
const heap = new Uint8Array(memory.buffer);
|
|
222
|
+
const process = state._process;
|
|
223
|
+
const out = state.out;
|
|
224
|
+
while (true) {
|
|
225
|
+
const result = process(state.streamHandle, 0, 0, out, outBufferSize, 4);
|
|
226
|
+
const code = (result >> 24) & 0xff;
|
|
227
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
228
|
+
if (signedCode < 0) {
|
|
229
|
+
throw new Error("process error:" + signedCode);
|
|
230
|
+
}
|
|
231
|
+
const produced = result & 0x00ffffff;
|
|
232
|
+
if (produced) {
|
|
233
|
+
enqueue(heap.slice(out, out + produced));
|
|
234
|
+
}
|
|
235
|
+
if (code === 1 || produced === 0) {
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
193
238
|
}
|
|
194
|
-
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function enqueue(chunk) {
|
|
242
|
+
backpressure = true;
|
|
243
|
+
readableController.enqueue(chunk);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function resumeWrite() {
|
|
247
|
+
if (resolveWrite) {
|
|
248
|
+
const resolve = resolveWrite;
|
|
249
|
+
resolveWrite = null;
|
|
250
|
+
resolve();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
195
253
|
|
|
196
254
|
function disposeStream(state) {
|
|
197
255
|
let endResult = 0;
|
|
@@ -43,11 +43,16 @@ function toCompatibleReadable(readable) {
|
|
|
43
43
|
const reader = readable.getReader();
|
|
44
44
|
return new ReadableStream({
|
|
45
45
|
async pull(controller) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
try {
|
|
47
|
+
const { value, done } = await reader.read();
|
|
48
|
+
if (done) {
|
|
49
|
+
controller.close();
|
|
50
|
+
} else {
|
|
51
|
+
controller.enqueue(value);
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
reader.cancel(error).catch(() => { });
|
|
55
|
+
throw error;
|
|
51
56
|
}
|
|
52
57
|
},
|
|
53
58
|
cancel(reason) {
|