zlib-streams 1.2.2 → 1.3.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/Makefile +4 -0
- package/dist/zlib-streams.js +190 -118
- package/package.json +1 -1
- package/src/wasm/api/zlib-streams.js +190 -118
package/Makefile
CHANGED
|
@@ -296,6 +296,10 @@ run_all_tests: dist/zlib-streams-dev.wasm
|
|
|
296
296
|
@node src/wasm/tests/test_output_buffer_boundary.js dist/zlib-streams-dev.wasm
|
|
297
297
|
# Error codes packed the same way as a success, on both directions
|
|
298
298
|
@node src/wasm/tests/test_process_error_encoding.js dist/zlib-streams-dev.wasm
|
|
299
|
+
# Buffers and zlib state released whichever end ends the stream, with no transformer hook
|
|
300
|
+
@node src/wasm/tests/test_stream_abort_releases_memory.js dist/zlib-streams-dev.wasm
|
|
301
|
+
# Bytes after the end of the stream rejected, as the platform inflaters do
|
|
302
|
+
@node src/wasm/tests/test_trailing_data.js dist/zlib-streams-dev.wasm
|
|
299
303
|
@echo "Completed run_all_tests"
|
|
300
304
|
|
|
301
305
|
dist/zlib-streams-dev.wasm: $(WASM_SRCS)
|
package/dist/zlib-streams.js
CHANGED
|
@@ -26,12 +26,14 @@
|
|
|
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";
|
|
33
33
|
const FORMAT_DEFLATE64_RAW = "deflate64-raw";
|
|
34
34
|
const FORMAT_GZIP = "gzip";
|
|
35
|
+
const Z_MEM_ERROR = -4;
|
|
36
|
+
const Z_MEM_ERROR_CODE = "Z_MEM_ERROR";
|
|
35
37
|
|
|
36
38
|
let wasm, malloc, free, memory, initError;
|
|
37
39
|
|
|
@@ -52,6 +54,13 @@ export function resetWasmExports() {
|
|
|
52
54
|
wasm = malloc = free = memory = initError = null;
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
function setZlibCode(error, result) {
|
|
58
|
+
if (result === Z_MEM_ERROR) {
|
|
59
|
+
error.code = Z_MEM_ERROR_CODE;
|
|
60
|
+
}
|
|
61
|
+
return error;
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
function _make(isCompress, type, options = {}) {
|
|
56
65
|
if (!wasm) {
|
|
57
66
|
const error = new Error("WASM module not loaded");
|
|
@@ -61,137 +70,200 @@ function _make(isCompress, type, options = {}) {
|
|
|
61
70
|
const level = (typeof options.level === "number") ? options.level : -1;
|
|
62
71
|
const outBufferSize = (typeof options.outBuffer === "number") ? options.outBuffer : 64 * 1024;
|
|
63
72
|
const inBufferSize = (typeof options.inBufferSize === "number") ? options.inBufferSize : 64 * 1024;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
const state = { out: 0, in: 0, inBufferSize: 0, streamHandle: 0, streamEnded: false };
|
|
74
|
+
let readableController, writableController, resolveWrite, cancelReason;
|
|
75
|
+
let backpressure = true;
|
|
76
|
+
let cancelled = false;
|
|
77
|
+
initStream();
|
|
78
|
+
const readable = new ReadableStream({
|
|
79
|
+
start(controller) {
|
|
80
|
+
readableController = controller;
|
|
81
|
+
},
|
|
82
|
+
pull() {
|
|
83
|
+
backpressure = false;
|
|
84
|
+
resumeWrite();
|
|
85
|
+
},
|
|
86
|
+
cancel(reason) {
|
|
87
|
+
cancelled = true;
|
|
88
|
+
cancelReason = reason;
|
|
89
|
+
disposeStream(state);
|
|
90
|
+
writableController.error(reason);
|
|
91
|
+
resumeWrite();
|
|
92
|
+
}
|
|
93
|
+
}, { highWaterMark: 0 });
|
|
94
|
+
const writable = new WritableStream({
|
|
95
|
+
start(controller) {
|
|
96
|
+
writableController = controller;
|
|
97
|
+
},
|
|
98
|
+
async write(chunk) {
|
|
99
|
+
if (backpressure) {
|
|
100
|
+
await new Promise(resolve => resolveWrite = resolve);
|
|
101
|
+
}
|
|
102
|
+
if (cancelled) {
|
|
103
|
+
throw cancelReason;
|
|
104
|
+
}
|
|
67
105
|
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
|
-
}
|
|
106
|
+
processChunk(chunk);
|
|
111
107
|
} catch (error) {
|
|
112
|
-
disposeStream(
|
|
108
|
+
disposeStream(state);
|
|
109
|
+
readableController.error(error);
|
|
113
110
|
throw error;
|
|
114
111
|
}
|
|
115
112
|
},
|
|
116
|
-
|
|
113
|
+
close() {
|
|
114
|
+
if (cancelled) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
117
|
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
|
-
}
|
|
118
|
+
flushStream();
|
|
155
119
|
} catch (error) {
|
|
156
|
-
disposeStream(
|
|
157
|
-
|
|
120
|
+
disposeStream(state);
|
|
121
|
+
readableController.error(error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
const result = disposeStream(state);
|
|
125
|
+
if (result !== 0) {
|
|
126
|
+
const error = setZlibCode(new Error("end error:" + result), result);
|
|
127
|
+
readableController.error(error);
|
|
128
|
+
throw error;
|
|
158
129
|
}
|
|
130
|
+
readableController.close();
|
|
159
131
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
132
|
+
abort(reason) {
|
|
133
|
+
disposeStream(state);
|
|
134
|
+
readableController.error(reason);
|
|
135
|
+
}
|
|
136
|
+
}, { highWaterMark: 1 });
|
|
137
|
+
return { readable, writable };
|
|
138
|
+
|
|
139
|
+
function initStream() {
|
|
140
|
+
try {
|
|
141
|
+
let result;
|
|
142
|
+
state.out = malloc(outBufferSize);
|
|
143
|
+
state.in = malloc(inBufferSize);
|
|
144
|
+
state.inBufferSize = inBufferSize;
|
|
145
|
+
if (!state.out || !state.in) {
|
|
146
|
+
throw setZlibCode(new Error("allocation failed"), Z_MEM_ERROR);
|
|
147
|
+
}
|
|
148
|
+
if (isCompress) {
|
|
149
|
+
state._process = wasm.deflate_process;
|
|
150
|
+
state._last_consumed = wasm.deflate_last_consumed;
|
|
151
|
+
state._end = wasm.deflate_end;
|
|
152
|
+
state.streamHandle = wasm.deflate_new();
|
|
153
|
+
if (type === FORMAT_GZIP) {
|
|
154
|
+
result = wasm.deflate_init_gzip(state.streamHandle, level);
|
|
155
|
+
} else if (type === FORMAT_DEFLATE_RAW) {
|
|
156
|
+
result = wasm.deflate_init_raw(state.streamHandle, level);
|
|
157
|
+
} else {
|
|
158
|
+
result = wasm.deflate_init(state.streamHandle, level);
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
if (type === FORMAT_DEFLATE64_RAW) {
|
|
162
|
+
state._process = wasm.inflate9_process;
|
|
163
|
+
state._last_consumed = wasm.inflate9_last_consumed;
|
|
164
|
+
state._end = wasm.inflate9_end;
|
|
165
|
+
state.streamHandle = wasm.inflate9_new();
|
|
166
|
+
result = wasm.inflate9_init_raw(state.streamHandle);
|
|
167
|
+
} else {
|
|
168
|
+
state._process = wasm.inflate_process;
|
|
169
|
+
state._last_consumed = wasm.inflate_last_consumed;
|
|
170
|
+
state._end = wasm.inflate_end;
|
|
171
|
+
state.streamHandle = wasm.inflate_new();
|
|
172
|
+
if (type === FORMAT_DEFLATE_RAW) {
|
|
173
|
+
result = wasm.inflate_init_raw(state.streamHandle);
|
|
174
|
+
} else if (type === FORMAT_GZIP) {
|
|
175
|
+
result = wasm.inflate_init_gzip(state.streamHandle);
|
|
176
|
+
} else {
|
|
177
|
+
result = wasm.inflate_init(state.streamHandle);
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
180
|
+
}
|
|
181
|
+
if (result !== 0) {
|
|
182
|
+
throw setZlibCode(new Error("init failed:" + result), result);
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
disposeStream(state);
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function processChunk(chunk) {
|
|
191
|
+
const heap = new Uint8Array(memory.buffer);
|
|
192
|
+
const process = state._process;
|
|
193
|
+
const last_consumed = state._last_consumed;
|
|
194
|
+
const out = state.out;
|
|
195
|
+
let offset = 0;
|
|
196
|
+
while (offset < chunk.length) {
|
|
197
|
+
if (state.streamEnded) {
|
|
198
|
+
throw new Error("trailing data after the end of the stream");
|
|
199
|
+
}
|
|
200
|
+
const toRead = Math.min(chunk.length - offset, 32 * 1024);
|
|
201
|
+
if (!state.in || state.inBufferSize < toRead) {
|
|
202
|
+
if (state.in && free) {
|
|
203
|
+
free(state.in);
|
|
204
|
+
state.in = 0;
|
|
205
|
+
}
|
|
206
|
+
state.in = malloc(toRead);
|
|
207
|
+
state.inBufferSize = toRead;
|
|
208
|
+
if (!state.in) {
|
|
209
|
+
throw setZlibCode(new Error("allocation failed"), Z_MEM_ERROR);
|
|
186
210
|
}
|
|
187
211
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
212
|
+
heap.set(chunk.subarray(offset, offset + toRead), state.in);
|
|
213
|
+
const result = process(state.streamHandle, state.in, toRead, out, outBufferSize, 0);
|
|
214
|
+
// checked before the byte count is used, so a status code can never be read as one
|
|
215
|
+
const code = (result >> 24) & 0xff;
|
|
216
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
217
|
+
if (signedCode < 0) {
|
|
218
|
+
throw setZlibCode(new Error("process error:" + signedCode), signedCode);
|
|
219
|
+
}
|
|
220
|
+
const prod = result & 0x00ffffff;
|
|
221
|
+
if (prod) {
|
|
222
|
+
enqueue(heap.slice(out, out + prod));
|
|
223
|
+
}
|
|
224
|
+
const consumed = last_consumed(state.streamHandle);
|
|
225
|
+
if (code === 1) {
|
|
226
|
+
state.streamEnded = true;
|
|
227
|
+
} else if (consumed === 0 && prod === 0) {
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
offset += consumed;
|
|
193
231
|
}
|
|
194
|
-
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function flushStream() {
|
|
235
|
+
const heap = new Uint8Array(memory.buffer);
|
|
236
|
+
const process = state._process;
|
|
237
|
+
const out = state.out;
|
|
238
|
+
while (true) {
|
|
239
|
+
const result = process(state.streamHandle, 0, 0, out, outBufferSize, 4);
|
|
240
|
+
const code = (result >> 24) & 0xff;
|
|
241
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
242
|
+
if (signedCode < 0) {
|
|
243
|
+
throw setZlibCode(new Error("process error:" + signedCode), signedCode);
|
|
244
|
+
}
|
|
245
|
+
const produced = result & 0x00ffffff;
|
|
246
|
+
if (produced) {
|
|
247
|
+
enqueue(heap.slice(out, out + produced));
|
|
248
|
+
}
|
|
249
|
+
if (code === 1 || produced === 0) {
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function enqueue(chunk) {
|
|
256
|
+
backpressure = true;
|
|
257
|
+
readableController.enqueue(chunk);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function resumeWrite() {
|
|
261
|
+
if (resolveWrite) {
|
|
262
|
+
const resolve = resolveWrite;
|
|
263
|
+
resolveWrite = null;
|
|
264
|
+
resolve();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
195
267
|
|
|
196
268
|
function disposeStream(state) {
|
|
197
269
|
let endResult = 0;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "WASM-based Compression Streams API implementation using zlib, with support for deflate64 decompression.",
|
|
4
4
|
"author": "Gildas Lormeau",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
|
-
"version": "1.
|
|
6
|
+
"version": "1.3.0",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"deflate",
|
|
@@ -26,12 +26,14 @@
|
|
|
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";
|
|
33
33
|
const FORMAT_DEFLATE64_RAW = "deflate64-raw";
|
|
34
34
|
const FORMAT_GZIP = "gzip";
|
|
35
|
+
const Z_MEM_ERROR = -4;
|
|
36
|
+
const Z_MEM_ERROR_CODE = "Z_MEM_ERROR";
|
|
35
37
|
|
|
36
38
|
let wasm, malloc, free, memory, initError;
|
|
37
39
|
|
|
@@ -52,6 +54,13 @@ export function resetWasmExports() {
|
|
|
52
54
|
wasm = malloc = free = memory = initError = null;
|
|
53
55
|
}
|
|
54
56
|
|
|
57
|
+
function setZlibCode(error, result) {
|
|
58
|
+
if (result === Z_MEM_ERROR) {
|
|
59
|
+
error.code = Z_MEM_ERROR_CODE;
|
|
60
|
+
}
|
|
61
|
+
return error;
|
|
62
|
+
}
|
|
63
|
+
|
|
55
64
|
function _make(isCompress, type, options = {}) {
|
|
56
65
|
if (!wasm) {
|
|
57
66
|
const error = new Error("WASM module not loaded");
|
|
@@ -61,137 +70,200 @@ function _make(isCompress, type, options = {}) {
|
|
|
61
70
|
const level = (typeof options.level === "number") ? options.level : -1;
|
|
62
71
|
const outBufferSize = (typeof options.outBuffer === "number") ? options.outBuffer : 64 * 1024;
|
|
63
72
|
const inBufferSize = (typeof options.inBufferSize === "number") ? options.inBufferSize : 64 * 1024;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
const state = { out: 0, in: 0, inBufferSize: 0, streamHandle: 0, streamEnded: false };
|
|
74
|
+
let readableController, writableController, resolveWrite, cancelReason;
|
|
75
|
+
let backpressure = true;
|
|
76
|
+
let cancelled = false;
|
|
77
|
+
initStream();
|
|
78
|
+
const readable = new ReadableStream({
|
|
79
|
+
start(controller) {
|
|
80
|
+
readableController = controller;
|
|
81
|
+
},
|
|
82
|
+
pull() {
|
|
83
|
+
backpressure = false;
|
|
84
|
+
resumeWrite();
|
|
85
|
+
},
|
|
86
|
+
cancel(reason) {
|
|
87
|
+
cancelled = true;
|
|
88
|
+
cancelReason = reason;
|
|
89
|
+
disposeStream(state);
|
|
90
|
+
writableController.error(reason);
|
|
91
|
+
resumeWrite();
|
|
92
|
+
}
|
|
93
|
+
}, { highWaterMark: 0 });
|
|
94
|
+
const writable = new WritableStream({
|
|
95
|
+
start(controller) {
|
|
96
|
+
writableController = controller;
|
|
97
|
+
},
|
|
98
|
+
async write(chunk) {
|
|
99
|
+
if (backpressure) {
|
|
100
|
+
await new Promise(resolve => resolveWrite = resolve);
|
|
101
|
+
}
|
|
102
|
+
if (cancelled) {
|
|
103
|
+
throw cancelReason;
|
|
104
|
+
}
|
|
67
105
|
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
|
-
}
|
|
106
|
+
processChunk(chunk);
|
|
111
107
|
} catch (error) {
|
|
112
|
-
disposeStream(
|
|
108
|
+
disposeStream(state);
|
|
109
|
+
readableController.error(error);
|
|
113
110
|
throw error;
|
|
114
111
|
}
|
|
115
112
|
},
|
|
116
|
-
|
|
113
|
+
close() {
|
|
114
|
+
if (cancelled) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
117
|
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
|
-
}
|
|
118
|
+
flushStream();
|
|
155
119
|
} catch (error) {
|
|
156
|
-
disposeStream(
|
|
157
|
-
|
|
120
|
+
disposeStream(state);
|
|
121
|
+
readableController.error(error);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
const result = disposeStream(state);
|
|
125
|
+
if (result !== 0) {
|
|
126
|
+
const error = setZlibCode(new Error("end error:" + result), result);
|
|
127
|
+
readableController.error(error);
|
|
128
|
+
throw error;
|
|
158
129
|
}
|
|
130
|
+
readableController.close();
|
|
159
131
|
},
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
132
|
+
abort(reason) {
|
|
133
|
+
disposeStream(state);
|
|
134
|
+
readableController.error(reason);
|
|
135
|
+
}
|
|
136
|
+
}, { highWaterMark: 1 });
|
|
137
|
+
return { readable, writable };
|
|
138
|
+
|
|
139
|
+
function initStream() {
|
|
140
|
+
try {
|
|
141
|
+
let result;
|
|
142
|
+
state.out = malloc(outBufferSize);
|
|
143
|
+
state.in = malloc(inBufferSize);
|
|
144
|
+
state.inBufferSize = inBufferSize;
|
|
145
|
+
if (!state.out || !state.in) {
|
|
146
|
+
throw setZlibCode(new Error("allocation failed"), Z_MEM_ERROR);
|
|
147
|
+
}
|
|
148
|
+
if (isCompress) {
|
|
149
|
+
state._process = wasm.deflate_process;
|
|
150
|
+
state._last_consumed = wasm.deflate_last_consumed;
|
|
151
|
+
state._end = wasm.deflate_end;
|
|
152
|
+
state.streamHandle = wasm.deflate_new();
|
|
153
|
+
if (type === FORMAT_GZIP) {
|
|
154
|
+
result = wasm.deflate_init_gzip(state.streamHandle, level);
|
|
155
|
+
} else if (type === FORMAT_DEFLATE_RAW) {
|
|
156
|
+
result = wasm.deflate_init_raw(state.streamHandle, level);
|
|
157
|
+
} else {
|
|
158
|
+
result = wasm.deflate_init(state.streamHandle, level);
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
if (type === FORMAT_DEFLATE64_RAW) {
|
|
162
|
+
state._process = wasm.inflate9_process;
|
|
163
|
+
state._last_consumed = wasm.inflate9_last_consumed;
|
|
164
|
+
state._end = wasm.inflate9_end;
|
|
165
|
+
state.streamHandle = wasm.inflate9_new();
|
|
166
|
+
result = wasm.inflate9_init_raw(state.streamHandle);
|
|
167
|
+
} else {
|
|
168
|
+
state._process = wasm.inflate_process;
|
|
169
|
+
state._last_consumed = wasm.inflate_last_consumed;
|
|
170
|
+
state._end = wasm.inflate_end;
|
|
171
|
+
state.streamHandle = wasm.inflate_new();
|
|
172
|
+
if (type === FORMAT_DEFLATE_RAW) {
|
|
173
|
+
result = wasm.inflate_init_raw(state.streamHandle);
|
|
174
|
+
} else if (type === FORMAT_GZIP) {
|
|
175
|
+
result = wasm.inflate_init_gzip(state.streamHandle);
|
|
176
|
+
} else {
|
|
177
|
+
result = wasm.inflate_init(state.streamHandle);
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
180
|
+
}
|
|
181
|
+
if (result !== 0) {
|
|
182
|
+
throw setZlibCode(new Error("init failed:" + result), result);
|
|
183
|
+
}
|
|
184
|
+
} catch (error) {
|
|
185
|
+
disposeStream(state);
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function processChunk(chunk) {
|
|
191
|
+
const heap = new Uint8Array(memory.buffer);
|
|
192
|
+
const process = state._process;
|
|
193
|
+
const last_consumed = state._last_consumed;
|
|
194
|
+
const out = state.out;
|
|
195
|
+
let offset = 0;
|
|
196
|
+
while (offset < chunk.length) {
|
|
197
|
+
if (state.streamEnded) {
|
|
198
|
+
throw new Error("trailing data after the end of the stream");
|
|
199
|
+
}
|
|
200
|
+
const toRead = Math.min(chunk.length - offset, 32 * 1024);
|
|
201
|
+
if (!state.in || state.inBufferSize < toRead) {
|
|
202
|
+
if (state.in && free) {
|
|
203
|
+
free(state.in);
|
|
204
|
+
state.in = 0;
|
|
205
|
+
}
|
|
206
|
+
state.in = malloc(toRead);
|
|
207
|
+
state.inBufferSize = toRead;
|
|
208
|
+
if (!state.in) {
|
|
209
|
+
throw setZlibCode(new Error("allocation failed"), Z_MEM_ERROR);
|
|
186
210
|
}
|
|
187
211
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
212
|
+
heap.set(chunk.subarray(offset, offset + toRead), state.in);
|
|
213
|
+
const result = process(state.streamHandle, state.in, toRead, out, outBufferSize, 0);
|
|
214
|
+
// checked before the byte count is used, so a status code can never be read as one
|
|
215
|
+
const code = (result >> 24) & 0xff;
|
|
216
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
217
|
+
if (signedCode < 0) {
|
|
218
|
+
throw setZlibCode(new Error("process error:" + signedCode), signedCode);
|
|
219
|
+
}
|
|
220
|
+
const prod = result & 0x00ffffff;
|
|
221
|
+
if (prod) {
|
|
222
|
+
enqueue(heap.slice(out, out + prod));
|
|
223
|
+
}
|
|
224
|
+
const consumed = last_consumed(state.streamHandle);
|
|
225
|
+
if (code === 1) {
|
|
226
|
+
state.streamEnded = true;
|
|
227
|
+
} else if (consumed === 0 && prod === 0) {
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
offset += consumed;
|
|
193
231
|
}
|
|
194
|
-
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function flushStream() {
|
|
235
|
+
const heap = new Uint8Array(memory.buffer);
|
|
236
|
+
const process = state._process;
|
|
237
|
+
const out = state.out;
|
|
238
|
+
while (true) {
|
|
239
|
+
const result = process(state.streamHandle, 0, 0, out, outBufferSize, 4);
|
|
240
|
+
const code = (result >> 24) & 0xff;
|
|
241
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
242
|
+
if (signedCode < 0) {
|
|
243
|
+
throw setZlibCode(new Error("process error:" + signedCode), signedCode);
|
|
244
|
+
}
|
|
245
|
+
const produced = result & 0x00ffffff;
|
|
246
|
+
if (produced) {
|
|
247
|
+
enqueue(heap.slice(out, out + produced));
|
|
248
|
+
}
|
|
249
|
+
if (code === 1 || produced === 0) {
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function enqueue(chunk) {
|
|
256
|
+
backpressure = true;
|
|
257
|
+
readableController.enqueue(chunk);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function resumeWrite() {
|
|
261
|
+
if (resolveWrite) {
|
|
262
|
+
const resolve = resolveWrite;
|
|
263
|
+
resolveWrite = null;
|
|
264
|
+
resolve();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
195
267
|
|
|
196
268
|
function disposeStream(state) {
|
|
197
269
|
let endResult = 0;
|