zlib-streams 1.0.7 → 1.1.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/Makefile +23 -8
- package/dist/zlib-streams-dev.wasm +0 -0
- package/dist/zlib-streams.js +145 -75
- package/dist/zlib-streams.wasm +0 -0
- package/package.json +2 -2
- package/src/README.md +61 -1
- package/src/chunkcopy.h +565 -0
- package/src/compare256.h +56 -0
- package/src/cpu_features.h +22 -0
- package/src/deflate.c +2349 -0
- package/src/deflate.h +420 -0
- package/src/deflate_crc32.c +22 -0
- package/src/inffast.h +26 -0
- package/src/{inffast.c → inffast_chunk.c} +127 -71
- package/src/inffast_chunk.h +42 -0
- package/src/inflate.c +69 -33
- package/src/insert_string.h +80 -0
- package/src/wasm/api/zlib-streams.js +145 -75
- package/src/wasm/wasm_stream_common.c +8 -4
- package/build/debug/src/inffast.d +0 -8
- package/build/debug/src/inffast.o +0 -0
- package/build/debug/src/inflate.d +0 -8
- package/build/debug/src/inflate.o +0 -0
- package/build/debug/src/inftrees.d +0 -6
- package/build/debug/src/inftrees.o +0 -0
- package/build/debug/src/zlib/adler32.d +0 -5
- package/build/debug/src/zlib/adler32.o +0 -0
- package/build/debug/src/zlib/contrib/infback9/infback9.d +0 -13
- package/build/debug/src/zlib/contrib/infback9/infback9.o +0 -0
- package/build/debug/src/zlib/contrib/infback9/inftree9.d +0 -7
- package/build/debug/src/zlib/contrib/infback9/inftree9.o +0 -0
- package/build/debug/src/zlib/crc32.d +0 -6
- package/build/debug/src/zlib/crc32.o +0 -0
- package/build/debug/src/zlib/trees.d +0 -7
- package/build/debug/src/zlib/trees.o +0 -0
- package/build/debug/src/zlib/zutil.d +0 -6
- package/build/debug/src/zlib/zutil.o +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__100k_lines.deflate64.log +0 -34
- package/tmp/all_runs/payload_decompress_nowindow_debug__100k_lines.deflate64.out +0 -100000
- package/tmp/all_runs/payload_decompress_nowindow_debug__10k_lines.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_nowindow_debug__10k_lines.deflate64.out +0 -10000
- package/tmp/all_runs/payload_decompress_nowindow_debug__payload_63k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_nowindow_debug__payload_63k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__payload_64k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_nowindow_debug__payload_64k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__payload_65k.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_nowindow_debug__payload_65k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__rand_block_gap.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_nowindow_debug__rand_block_gap.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__repeat_63k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_nowindow_debug__repeat_63k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__repeat_64k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_nowindow_debug__repeat_64k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__repeat_65k.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_nowindow_debug__repeat_65k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_nowindow_debug__zeros_100k.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_nowindow_debug__zeros_100k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__100k_lines.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__100k_lines.deflate64.out +0 -100000
- package/tmp/all_runs/payload_decompress_ref_debug__10k_lines.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__10k_lines.deflate64.out +0 -10000
- package/tmp/all_runs/payload_decompress_ref_debug__payload_63k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__payload_63k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__payload_64k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__payload_64k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__payload_65k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__payload_65k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__rand_block_gap.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__rand_block_gap.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__repeat_63k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__repeat_63k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__repeat_64k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__repeat_64k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__repeat_65k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__repeat_65k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_ref_debug__zeros_100k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_ref_debug__zeros_100k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__100k_lines.deflate64.log +0 -34
- package/tmp/all_runs/payload_decompress_test_debug__100k_lines.deflate64.out +0 -100000
- package/tmp/all_runs/payload_decompress_test_debug__10k_lines.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_test_debug__10k_lines.deflate64.out +0 -10000
- package/tmp/all_runs/payload_decompress_test_debug__payload_63k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_test_debug__payload_63k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__payload_64k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_test_debug__payload_64k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__payload_65k.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_test_debug__payload_65k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__rand_block_gap.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_test_debug__rand_block_gap.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__repeat_63k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_test_debug__repeat_63k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__repeat_64k.deflate64.log +0 -1
- package/tmp/all_runs/payload_decompress_test_debug__repeat_64k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__repeat_65k.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_test_debug__repeat_65k.deflate64.out +0 -0
- package/tmp/all_runs/payload_decompress_test_debug__zeros_100k.deflate64.log +0 -2
- package/tmp/all_runs/payload_decompress_test_debug__zeros_100k.deflate64.out +0 -0
- package/tmp/all_runs/wasm__100k_lines.deflate64.out +0 -100000
- package/tmp/all_runs/wasm__10k_lines.deflate64.out +0 -10000
- package/tmp/all_runs/wasm__payload_63k.deflate64.out +0 -0
- package/tmp/all_runs/wasm__payload_64k.deflate64.out +0 -0
- package/tmp/all_runs/wasm__payload_65k.deflate64.out +0 -0
- package/tmp/all_runs/wasm__rand_block_gap.deflate64.out +0 -0
- package/tmp/all_runs/wasm__repeat_63k.deflate64.out +0 -0
- package/tmp/all_runs/wasm__repeat_64k.deflate64.out +0 -0
- package/tmp/all_runs/wasm__repeat_65k.deflate64.out +0 -0
- package/tmp/all_runs/wasm__zeros_100k.deflate64.out +0 -0
- package/tmp/diagnose/diagnose_stream_mem.json +0 -4202
package/Makefile
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
CC=gcc
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
# INFLATE_CHUNK_GENERIC selects the portable chunk copies in chunkcopy.h, which has
|
|
3
|
+
# no wasm SIMD path and would #error without one of its three arch macros.
|
|
4
|
+
# INFLATE_CHUNK_READ_64LE buffers the input bits in a uint64_t inside inffast_chunk.c
|
|
5
|
+
# only; state->hold stays unsigned long. Both are needed wherever inflate.c is built.
|
|
6
|
+
INFLATE_CHUNK_CFLAGS = -DINFLATE_CHUNK_GENERIC -DINFLATE_CHUNK_READ_64LE
|
|
7
|
+
CFLAGS=-I./src/zlib -I./src -I./test -I./src/zlib/contrib/infback9 -O2 -w -MMD -MP $(INFLATE_CHUNK_CFLAGS)
|
|
8
|
+
DEBUG_CFLAGS=-I./src/zlib -I./src -I./test -I./src/zlib/contrib/infback9 -O0 -g3 -ggdb3 -fno-inline -fno-omit-frame-pointer -w -MMD -MP $(INFLATE_CHUNK_CFLAGS)
|
|
4
9
|
## By default we don't enable the INF9 tracing macros so debug binaries
|
|
5
10
|
## don't embed large diagnostic strings. To enable tracing for local
|
|
6
11
|
## debugging, uncomment and set DEBUG_DEFINES accordingly.
|
|
@@ -9,17 +14,17 @@ DEBUG_CFLAGS=-I./src/zlib -I./src -I./test -I./src/zlib/contrib/infback9 -O0 -g3
|
|
|
9
14
|
## Debug defines are disabled by default for a clean commit-ready Makefile.
|
|
10
15
|
DEBUG_DEFINES=
|
|
11
16
|
DEBUG_DEFINES_TRACED=
|
|
12
|
-
SRC=src/inflate.c src/
|
|
17
|
+
SRC=src/inflate.c src/inffast_chunk.c src/inftrees.c src/zlib/zutil.c
|
|
13
18
|
TESTSRC=zlib/crc32.c
|
|
14
19
|
LIBS=-lz
|
|
15
20
|
|
|
16
21
|
## Build the payload decompressor test binary used for verification (deduplicated sources)
|
|
17
22
|
PD_SRCS = test/payload_decompress.c \
|
|
18
|
-
src/inflate.c src/
|
|
23
|
+
src/inflate.c src/inffast_chunk.c src/inftrees.c src/zlib/zutil.c \
|
|
19
24
|
src/zlib/crc32.c src/zlib/adler32.c
|
|
20
25
|
|
|
21
26
|
PD_NOWINDOW_SRCS = test/payload_decompress_nowindow.c \
|
|
22
|
-
src/inflate.c src/
|
|
27
|
+
src/inflate.c src/inffast_chunk.c src/inftrees.c src/zlib/zutil.c \
|
|
23
28
|
src/zlib/crc32.c src/zlib/adler32.c
|
|
24
29
|
|
|
25
30
|
PD_NOWINDOW_DEBUG_OBJS = $(PD_NOWINDOW_SRCS:%.c=build/debug/%.o)
|
|
@@ -131,14 +136,19 @@ EMCC ?= emsdk/upstream/emscripten/emcc
|
|
|
131
136
|
WASM_OPT ?= emsdk/upstream/bin/wasm-opt
|
|
132
137
|
|
|
133
138
|
WASM_SRCS = src/wasm/inflate9_stream_wasm.c src/wasm/inflate_stream_wasm.c src/wasm/deflate_stream_wasm.c src/wasm/wasm_stream_common.c src/wasm/allocator.c \
|
|
134
|
-
src/inflate.c src/
|
|
135
|
-
src/zlib/crc32.c src/zlib/adler32.c src/trees.c src/
|
|
139
|
+
src/inflate.c src/inffast_chunk.c src/inftrees.c src/zlib/zutil.c \
|
|
140
|
+
src/zlib/crc32.c src/zlib/adler32.c src/trees.c src/deflate.c src/deflate_crc32.c
|
|
136
141
|
# CRC-32: -DZ_SOLO suppresses zlib's Z_U4/Z_U8 word types, which makes crc32.c's braid
|
|
137
142
|
# path (#elif defined(Z_U4)) fall back to a byte-at-a-time loop. Restore the types and
|
|
138
143
|
# force the 8-byte braid (Z_TESTW=8) so the slicing/braided CRC compiles for wasm:
|
|
139
144
|
# ~12x faster CRC (342 -> ~4100 MB/s), bit-identical output. wasm32 has native i64.
|
|
140
145
|
WASM_CRC_CFLAGS = -DZ_U4=unsigned -DZ_U8='unsigned long long' -DZ_TESTW=8
|
|
141
|
-
|
|
146
|
+
# DEFLATE_COMPARE256_64LE extends matches 8 bytes at a time in longest_match, which is
|
|
147
|
+
# the same match length computed faster: ~7% at every level, byte-identical output.
|
|
148
|
+
# USE_ZLIB_RABIN_KARP_ROLLING_HASH turns Chromium's own hash OFF so the deflate stream
|
|
149
|
+
# stays bit-for-bit what madler's deflate.c produces.
|
|
150
|
+
WASM_DEFLATE_CFLAGS = -DDEFLATE_COMPARE256_64LE -DUSE_ZLIB_RABIN_KARP_ROLLING_HASH
|
|
151
|
+
WASM_CFLAGS = -Isrc -Isrc/zlib -Isrc/zlib/contrib/infback9 -O2 -flto -DDYNAMIC_CRC_TABLE -DBUILDFIXED -DZ_SOLO $(WASM_CRC_CFLAGS) $(WASM_DEFLATE_CFLAGS) $(INFLATE_CHUNK_CFLAGS)
|
|
142
152
|
|
|
143
153
|
.PHONY: wasm
|
|
144
154
|
wasm: dist/zlib-streams-dev.wasm
|
|
@@ -279,6 +289,11 @@ run_all_tests: dist/zlib-streams-dev.wasm
|
|
|
279
289
|
@node src/wasm/tests/run_roundtrip_cli.js deflate 24000 dist/zlib-streams-dev.wasm
|
|
280
290
|
@$(MAKE) run_transform_roundtrip
|
|
281
291
|
@$(MAKE) test_decompressionstream_inflate9
|
|
292
|
+
# Output buffer filling before any input is consumed, including a deflate64
|
|
293
|
+
# match longer than the buffer, which no encoder we have can produce
|
|
294
|
+
@node src/wasm/tests/test_output_buffer_boundary.js dist/zlib-streams-dev.wasm
|
|
295
|
+
# Error codes packed the same way as a success, on both directions
|
|
296
|
+
@node src/wasm/tests/test_process_error_encoding.js dist/zlib-streams-dev.wasm
|
|
282
297
|
@echo "Completed run_all_tests"
|
|
283
298
|
|
|
284
299
|
dist/zlib-streams-dev.wasm: $(WASM_SRCS)
|
|
Binary file
|
package/dist/zlib-streams.js
CHANGED
|
@@ -1,7 +1,39 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
1
|
+
/*
|
|
2
|
+
Copyright (c) 2025 Gildas Lormeau. All rights reserved.
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
8
|
+
this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in
|
|
12
|
+
the documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. The names of the authors may not be used to endorse or promote products
|
|
15
|
+
derived from this software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
18
|
+
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
|
|
20
|
+
INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
21
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
22
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
23
|
+
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
26
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/* global TransformStream */
|
|
30
|
+
|
|
31
|
+
const FORMAT_DEFLATE = "deflate";
|
|
32
|
+
const FORMAT_DEFLATE_RAW = "deflate-raw";
|
|
33
|
+
const FORMAT_DEFLATE64_RAW = "deflate64-raw";
|
|
34
|
+
const FORMAT_GZIP = "gzip";
|
|
35
|
+
|
|
36
|
+
let wasm, malloc, free, memory, initError;
|
|
5
37
|
|
|
6
38
|
export function setWasmExports(wasmAPI) {
|
|
7
39
|
wasm = wasmAPI;
|
|
@@ -12,53 +44,74 @@ export function setWasmExports(wasmAPI) {
|
|
|
12
44
|
}
|
|
13
45
|
}
|
|
14
46
|
|
|
47
|
+
export function setInitError(error) {
|
|
48
|
+
initError = error;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function resetWasmExports() {
|
|
52
|
+
wasm = malloc = free = memory = initError = null;
|
|
53
|
+
}
|
|
54
|
+
|
|
15
55
|
function _make(isCompress, type, options = {}) {
|
|
56
|
+
if (!wasm) {
|
|
57
|
+
const error = new Error("WASM module not loaded");
|
|
58
|
+
error.cause = initError;
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
16
61
|
const level = (typeof options.level === "number") ? options.level : -1;
|
|
17
62
|
const outBufferSize = (typeof options.outBuffer === "number") ? options.outBuffer : 64 * 1024;
|
|
18
63
|
const inBufferSize = (typeof options.inBufferSize === "number") ? options.inBufferSize : 64 * 1024;
|
|
19
64
|
|
|
20
65
|
return new TransformStream({
|
|
21
66
|
start() {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this._last_consumed = wasm.deflate_last_consumed;
|
|
30
|
-
this._end = wasm.deflate_end;
|
|
31
|
-
this.streamHandle = wasm.deflate_new();
|
|
32
|
-
if (type === "gzip") {
|
|
33
|
-
result = wasm.deflate_init_gzip(this.streamHandle, level);
|
|
34
|
-
} else if (type === "deflate-raw") {
|
|
35
|
-
result = wasm.deflate_init_raw(this.streamHandle, level);
|
|
36
|
-
} else {
|
|
37
|
-
result = wasm.deflate_init(this.streamHandle, level);
|
|
67
|
+
try {
|
|
68
|
+
let result;
|
|
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");
|
|
38
74
|
}
|
|
39
|
-
|
|
40
|
-
if (
|
|
41
|
-
this._process = wasm.
|
|
42
|
-
this._last_consumed = wasm.
|
|
43
|
-
this._end = wasm.
|
|
44
|
-
this.streamHandle = wasm.
|
|
45
|
-
|
|
75
|
+
this._scratch = new Uint8Array(outBufferSize);
|
|
76
|
+
if (isCompress) {
|
|
77
|
+
this._process = wasm.deflate_process;
|
|
78
|
+
this._last_consumed = wasm.deflate_last_consumed;
|
|
79
|
+
this._end = wasm.deflate_end;
|
|
80
|
+
this.streamHandle = wasm.deflate_new();
|
|
81
|
+
if (type === FORMAT_GZIP) {
|
|
82
|
+
result = wasm.deflate_init_gzip(this.streamHandle, level);
|
|
83
|
+
} else if (type === FORMAT_DEFLATE_RAW) {
|
|
84
|
+
result = wasm.deflate_init_raw(this.streamHandle, level);
|
|
85
|
+
} else {
|
|
86
|
+
result = wasm.deflate_init(this.streamHandle, level);
|
|
87
|
+
}
|
|
46
88
|
} else {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
result = wasm.
|
|
53
|
-
} else if (type === "gzip") {
|
|
54
|
-
result = wasm.inflate_init_gzip(this.streamHandle);
|
|
89
|
+
if (type === FORMAT_DEFLATE64_RAW) {
|
|
90
|
+
this._process = wasm.inflate9_process;
|
|
91
|
+
this._last_consumed = wasm.inflate9_last_consumed;
|
|
92
|
+
this._end = wasm.inflate9_end;
|
|
93
|
+
this.streamHandle = wasm.inflate9_new();
|
|
94
|
+
result = wasm.inflate9_init_raw(this.streamHandle);
|
|
55
95
|
} else {
|
|
56
|
-
|
|
96
|
+
this._process = wasm.inflate_process;
|
|
97
|
+
this._last_consumed = wasm.inflate_last_consumed;
|
|
98
|
+
this._end = wasm.inflate_end;
|
|
99
|
+
this.streamHandle = wasm.inflate_new();
|
|
100
|
+
if (type === FORMAT_DEFLATE_RAW) {
|
|
101
|
+
result = wasm.inflate_init_raw(this.streamHandle);
|
|
102
|
+
} else if (type === FORMAT_GZIP) {
|
|
103
|
+
result = wasm.inflate_init_gzip(this.streamHandle);
|
|
104
|
+
} else {
|
|
105
|
+
result = wasm.inflate_init(this.streamHandle);
|
|
106
|
+
}
|
|
57
107
|
}
|
|
58
108
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
109
|
+
if (result !== 0) {
|
|
110
|
+
throw new Error("init failed:" + result);
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
disposeStream(this);
|
|
114
|
+
throw error;
|
|
62
115
|
}
|
|
63
116
|
},
|
|
64
117
|
transform(chunk, controller) {
|
|
@@ -75,40 +128,35 @@ function _make(isCompress, type, options = {}) {
|
|
|
75
128
|
if (!this.in || this.inBufferSize < toRead) {
|
|
76
129
|
if (this.in && free) {
|
|
77
130
|
free(this.in);
|
|
131
|
+
this.in = 0;
|
|
78
132
|
}
|
|
79
133
|
this.in = malloc(toRead);
|
|
80
134
|
this.inBufferSize = toRead;
|
|
135
|
+
if (!this.in) {
|
|
136
|
+
throw new Error("allocation failed");
|
|
137
|
+
}
|
|
81
138
|
}
|
|
82
139
|
heap.set(buffer.subarray(offset, offset + toRead), this.in);
|
|
83
140
|
const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
|
|
141
|
+
// checked before the byte count is used, so a status code can never be read as one
|
|
142
|
+
const code = (result >> 24) & 0xff;
|
|
143
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
144
|
+
if (signedCode < 0) {
|
|
145
|
+
throw new Error("process error:" + signedCode);
|
|
146
|
+
}
|
|
84
147
|
const prod = result & 0x00ffffff;
|
|
85
148
|
if (prod) {
|
|
86
149
|
scratch.set(heap.subarray(out, out + prod), 0);
|
|
87
150
|
controller.enqueue(scratch.slice(0, prod));
|
|
88
151
|
}
|
|
89
|
-
if (!isCompress) {
|
|
90
|
-
const code = (result >> 24) & 0xff;
|
|
91
|
-
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
92
|
-
if (signedCode < 0) {
|
|
93
|
-
throw new Error("process error:" + signedCode);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
152
|
const consumed = last_consumed(this.streamHandle);
|
|
97
|
-
if (consumed === 0) {
|
|
153
|
+
if (consumed === 0 && prod === 0) {
|
|
98
154
|
break;
|
|
99
155
|
}
|
|
100
156
|
offset += consumed;
|
|
101
157
|
}
|
|
102
158
|
} catch (error) {
|
|
103
|
-
|
|
104
|
-
this._end(this.streamHandle);
|
|
105
|
-
}
|
|
106
|
-
if (this.in && free) {
|
|
107
|
-
free(this.in);
|
|
108
|
-
}
|
|
109
|
-
if (this.out && free) {
|
|
110
|
-
free(this.out);
|
|
111
|
-
}
|
|
159
|
+
disposeStream(this);
|
|
112
160
|
controller.error(error);
|
|
113
161
|
}
|
|
114
162
|
},
|
|
@@ -120,14 +168,12 @@ function _make(isCompress, type, options = {}) {
|
|
|
120
168
|
const scratch = this._scratch;
|
|
121
169
|
while (true) {
|
|
122
170
|
const result = process(this.streamHandle, 0, 0, out, outBufferSize, 4);
|
|
123
|
-
const produced = result & 0x00ffffff;
|
|
124
171
|
const code = (result >> 24) & 0xff;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
throw new Error("process error:" + signedCode);
|
|
129
|
-
}
|
|
172
|
+
const signedCode = (code & 0x80) ? code - 256 : code;
|
|
173
|
+
if (signedCode < 0) {
|
|
174
|
+
throw new Error("process error:" + signedCode);
|
|
130
175
|
}
|
|
176
|
+
const produced = result & 0x00ffffff;
|
|
131
177
|
if (produced) {
|
|
132
178
|
scratch.set(heap.subarray(out, out + produced), 0);
|
|
133
179
|
controller.enqueue(scratch.slice(0, produced));
|
|
@@ -139,30 +185,54 @@ function _make(isCompress, type, options = {}) {
|
|
|
139
185
|
} catch (error) {
|
|
140
186
|
controller.error(error);
|
|
141
187
|
} finally {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
controller.error(new Error("end error:" + result));
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (this.in && free) {
|
|
149
|
-
free(this.in);
|
|
150
|
-
}
|
|
151
|
-
if (this.out && free) {
|
|
152
|
-
free(this.out);
|
|
188
|
+
const result = disposeStream(this);
|
|
189
|
+
if (result !== 0) {
|
|
190
|
+
controller.error(new Error("end error:" + result));
|
|
153
191
|
}
|
|
154
192
|
}
|
|
193
|
+
},
|
|
194
|
+
cancel() {
|
|
195
|
+
// release the stream handle and buffers when the pipeline is aborted,
|
|
196
|
+
// they would be leaked in the process-lifetime wasm heap otherwise
|
|
197
|
+
disposeStream(this);
|
|
155
198
|
}
|
|
156
199
|
});
|
|
200
|
+
|
|
201
|
+
function disposeStream(state) {
|
|
202
|
+
let endResult = 0;
|
|
203
|
+
if (state.streamHandle && state._end) {
|
|
204
|
+
endResult = state._end(state.streamHandle);
|
|
205
|
+
}
|
|
206
|
+
state.streamHandle = 0;
|
|
207
|
+
if (state.in && free) {
|
|
208
|
+
free(state.in);
|
|
209
|
+
}
|
|
210
|
+
state.in = 0;
|
|
211
|
+
if (state.out && free) {
|
|
212
|
+
free(state.out);
|
|
213
|
+
}
|
|
214
|
+
state.out = 0;
|
|
215
|
+
return endResult;
|
|
216
|
+
}
|
|
157
217
|
}
|
|
158
218
|
|
|
159
219
|
export class CompressionStreamZlib {
|
|
160
|
-
constructor(type =
|
|
220
|
+
constructor(type = FORMAT_DEFLATE, options) {
|
|
161
221
|
return _make(true, type, options);
|
|
162
222
|
}
|
|
163
223
|
}
|
|
164
224
|
export class DecompressionStreamZlib {
|
|
165
|
-
constructor(type =
|
|
225
|
+
constructor(type = FORMAT_DEFLATE, options) {
|
|
166
226
|
return _make(false, type, options);
|
|
167
227
|
}
|
|
168
|
-
}
|
|
228
|
+
}
|
|
229
|
+
// These codecs are backed by the WASM module; they are unusable until setWasmExports() has run.
|
|
230
|
+
// The worker uses this flag to know it must fall back to the native CompressionStream when the
|
|
231
|
+
// module fails to load, rather than discarding a self-contained codec supplied through config.
|
|
232
|
+
CompressionStreamZlib.requiresModule = true;
|
|
233
|
+
DecompressionStreamZlib.requiresModule = true;
|
|
234
|
+
// Constructing these classes before the module is loaded throws, so capability probes cannot rely
|
|
235
|
+
// on trying the constructor; the formats are declared instead, next to the branches implementing
|
|
236
|
+
// them in _make().
|
|
237
|
+
CompressionStreamZlib.supportedFormats = [FORMAT_DEFLATE, FORMAT_DEFLATE_RAW, FORMAT_GZIP];
|
|
238
|
+
DecompressionStreamZlib.supportedFormats = [FORMAT_DEFLATE, FORMAT_DEFLATE_RAW, FORMAT_GZIP, FORMAT_DEFLATE64_RAW];
|
package/dist/zlib-streams.wasm
CHANGED
|
Binary file
|
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.1.1",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"keywords": [
|
|
9
9
|
"deflate",
|
|
@@ -28,4 +28,4 @@
|
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
30
30
|
}
|
|
31
|
-
}
|
|
31
|
+
}
|
package/src/README.md
CHANGED
|
@@ -1 +1,61 @@
|
|
|
1
|
-
|
|
1
|
+
# Sources
|
|
2
|
+
|
|
3
|
+
`src/zlib` is a submodule of [madler/zlib](https://github.com/madler/zlib) and is never edited. The
|
|
4
|
+
files directly under `src/` are forked copies, compiled instead of their submodule counterparts. The
|
|
5
|
+
deflate64 work is described in <https://github.com/gildas-lormeau/inflate9.c>.
|
|
6
|
+
|
|
7
|
+
## Forked from madler/zlib
|
|
8
|
+
|
|
9
|
+
| file | why it is forked |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `inftrees.c`, `inftrees.h` | deflate64 length code 285 and distance codes 30 and 31 |
|
|
12
|
+
| `trees.c` | builds the static deflate trees at run time instead of embedding them |
|
|
13
|
+
|
|
14
|
+
## Forked from Chromium's zlib
|
|
15
|
+
|
|
16
|
+
`deflate.c`, `deflate.h`, `compare256.h`, `insert_string.h`, `cpu_features.h`, `inflate.c`,
|
|
17
|
+
`inffast.h`, `inffast_chunk.c`, `inffast_chunk.h` and `chunkcopy.h` come from
|
|
18
|
+
<https://chromium.googlesource.com/chromium/src/third_party/zlib>, revision
|
|
19
|
+
`285e94b8fa95ad3b7d16b80798ec8dce6febb8c8`. They are BSD-licensed, see the headers in the files.
|
|
20
|
+
`inflate.c`, `inffast_chunk.*` and `chunkcopy.h` are their `contrib/optimizations` versions.
|
|
21
|
+
|
|
22
|
+
`inflate.c` still carries the deflate64 support on top. That merge is small because the two are
|
|
23
|
+
orthogonal: deflate64 never enters `inflate_fast`, so the chunked fast path does not know about it.
|
|
24
|
+
|
|
25
|
+
### Build options
|
|
26
|
+
|
|
27
|
+
Deflate, in `WASM_DEFLATE_CFLAGS`:
|
|
28
|
+
|
|
29
|
+
- `DEFLATE_COMPARE256_64LE` extends matches 8 bytes at a time in `longest_match`. Same match length,
|
|
30
|
+
computed faster. About 7% at every level.
|
|
31
|
+
- `USE_ZLIB_RABIN_KARP_ROLLING_HASH` turns Chromium's own hash off, so the deflate stream stays
|
|
32
|
+
bit-for-bit what madler's `deflate.c` produces. Dropping this flag enables the faster ANZAC hash,
|
|
33
|
+
which is valid DEFLATE but different bytes.
|
|
34
|
+
|
|
35
|
+
Inflate, in `INFLATE_CHUNK_CFLAGS`, needed by every target that builds `inflate.c`, not only the
|
|
36
|
+
wasm one:
|
|
37
|
+
|
|
38
|
+
- `INFLATE_CHUNK_GENERIC` selects the portable chunk copies. `chunkcopy.h` has no wasm SIMD path and
|
|
39
|
+
`#error`s without one of its three arch macros. `-msimd128` was measured and buys nothing.
|
|
40
|
+
- `INFLATE_CHUNK_READ_64LE` buffers the input bits in a `uint64_t` inside `inffast_chunk.c` only.
|
|
41
|
+
`state->hold` stays `unsigned long`. Together they are worth about 20%.
|
|
42
|
+
|
|
43
|
+
### Deliberate edits, to re-apply when the Chromium files are updated
|
|
44
|
+
|
|
45
|
+
1. `deflate.c`, `inflate.c` and `inffast_chunk.c` include `"insert_string.h"`, `"inffast_chunk.h"`
|
|
46
|
+
and `"chunkcopy.h"` directly, not through `contrib/optimizations/`, because this repo keeps
|
|
47
|
+
forked zlib sources flat.
|
|
48
|
+
2. `deflate.h` leaves `LIT_MEM` off, as madler does. Chromium turns it on, which costs 16 KB of
|
|
49
|
+
`pending_buf` per deflate stream for about 1.5% of speed. The wasm heap is fixed at 16.9 MB, so
|
|
50
|
+
that is 62 concurrent deflate streams instead of 59.
|
|
51
|
+
3. `deflate.h` casts the arguments of `zmemcpy` and `zmemzero`. Chromium's `zutil.h` declares them
|
|
52
|
+
taking `void *`, madler's takes `Bytef *`, and this build keeps madler's.
|
|
53
|
+
4. `inflate.c` keeps the 9-bit and 6-bit root tables instead of Chromium's 10 and 9. Theirs need
|
|
54
|
+
`ENOUGH_LENS` raised from 852 to 1332, which is 1920 more bytes per inflate state and a fifth of
|
|
55
|
+
the concurrent inflate streams, for about 1% of speed. Without that change to `inftrees.h` they
|
|
56
|
+
fail every dynamic block with "invalid literal/lengths set".
|
|
57
|
+
5. `chunkcopy.h` includes `<stddef.h>` for `ptrdiff_t`, which `-DZ_SOLO` keeps `zutil.h` from
|
|
58
|
+
pulling in.
|
|
59
|
+
|
|
60
|
+
`deflate_crc32.c` supplies `crc_reset`, `crc_finalize` and `copy_with_crc`. Chromium's `crc32.c` owns
|
|
61
|
+
them and `deflate.c` calls them on the gzip path, but this build keeps madler's `crc32.c`.
|