zlib-streams 1.0.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/.clang-format ADDED
@@ -0,0 +1,3 @@
1
+ BasedOnStyle: LLVM
2
+ ReorderIncludes: false
3
+ SortIncludes: false
package/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "src/zlib"]
2
+ path = src/zlib
3
+ url = https://github.com/madler/zlib.git
@@ -0,0 +1,5 @@
1
+ # Ignore C and C++ source and headers in this repo
2
+ **/*.c
3
+ **/*.h
4
+ **/*.cpp
5
+ **/*.hpp
package/Makefile ADDED
@@ -0,0 +1,441 @@
1
+ CC=gcc
2
+ CFLAGS=-I./src/zlib -I./src -I./test -I./src/zlib/contrib/infback9 -O2 -w -MMD -MP
3
+ 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
4
+ ## By default we don't enable the INF9 tracing macros so debug binaries
5
+ ## don't embed large diagnostic strings. To enable tracing for local
6
+ ## debugging, uncomment and set DEBUG_DEFINES accordingly.
7
+ # Enable zlib's Tracev/Tracevv debug output and inf9 trace hooks for debug builds
8
+ # For traced wasm runs we enable INF9_TRACE via DEBUG_DEFINES_TRACED (used by the traced-wasm target)
9
+ ## Debug defines are disabled by default for a clean commit-ready Makefile.
10
+ DEBUG_DEFINES=
11
+ DEBUG_DEFINES_TRACED=
12
+ SRC=src/inflate9.c src/zlib/contrib/infback9/inftree9.c src/zlib/zutil.c src/zlib/inflate.c src/zlib/inftrees.c
13
+ TESTSRC=zlib/crc32.c
14
+ LIBS=-lz
15
+
16
+ ## Build the payload decompressor test binary used for verification (deduplicated sources)
17
+ PD_SRCS = test/payload_decompress.c \
18
+ src/inflate9.c src/zlib/inffast.c src/zlib/inftrees.c src/zlib/zutil.c src/zlib/inflate.c src/zlib/infback.c \
19
+ src/zlib/contrib/infback9/infback9.c src/zlib/contrib/infback9/inftree9.c src/zlib/crc32.c src/zlib/adler32.c src/zlib/trees.c
20
+
21
+ PD_NOWINDOW_SRCS = test/payload_decompress_nowindow.c \
22
+ src/inflate9.c src/zlib/inffast.c src/zlib/inftrees.c src/zlib/zutil.c src/zlib/inflate.c src/zlib/infback.c \
23
+ src/zlib/contrib/infback9/infback9.c src/zlib/contrib/infback9/inftree9.c src/zlib/crc32.c src/zlib/adler32.c src/zlib/trees.c
24
+
25
+ PD_NOWINDOW_DEBUG_OBJS = $(PD_NOWINDOW_SRCS:%.c=build/debug/%.o)
26
+
27
+ # Dedicated reference test that uses inflateBack9 (infback9.c) directly
28
+ PD_REF_SRCS = test/payload_decompress_ref.c \
29
+ src/zlib/contrib/infback9/infback9.c src/zlib/contrib/infback9/inftree9.c src/zlib/crc32.c src/zlib/adler32.c src/zlib/trees.c src/zlib/zutil.c
30
+
31
+ PD_REF_OBJS = $(PD_REF_SRCS:%.c=build/debug/%.o)
32
+ PD_REF_OBJS_RELEASE = $(PD_REF_SRCS:%.c=build/%.o)
33
+
34
+ # object paths for release and debug builds
35
+ PD_OBJS = $(PD_SRCS:%.c=build/%.o)
36
+ PD_DEBUG_OBJS = $(PD_SRCS:%.c=build/debug/%.o)
37
+
38
+ all: test_all
39
+
40
+ clean:
41
+ @echo "Cleaning build artifacts, dist, tmp, and generated files"
42
+ rm -rf ./test/payload_decompress_test_debug ./test/payload_decompress_ref_debug ./test/payload_decompress_test_debug.* ./test/payload_decompress_ref_debug.* build tmp *.d dist/*.wasm tmp/all_runs tmp/run_all_verify.log
43
+ # remove node generated artifacts if present
44
+ rm -f src/wasm/tests/*.out || true
45
+
46
+ test/payload_decompress_test: $(PD_OBJS)
47
+ mkdir -p test
48
+ $(CC) $(CFLAGS) $(PD_OBJS) -o $@
49
+
50
+ # Debug variant of the payload decompressor (with debug symbols)
51
+ test_all: test/payload_decompress_test test/payload_decompress_test_debug test/payload_decompress_ref test/payload_decompress_ref_debug
52
+ @echo "Built test binaries: test/payload_decompress_test test/payload_decompress_test_debug test/payload_decompress_ref test/payload_decompress_ref_debug"
53
+
54
+ # Build-only debug target used by IDEs (compile only, do not run)
55
+ test/payload_decompress_test_debug: $(PD_DEBUG_OBJS)
56
+ mkdir -p test
57
+ $(CC) $(DEBUG_DEFINES) $(DEBUG_CFLAGS) $(PD_DEBUG_OBJS) -o $@
58
+ @echo "Debug binary built: $@"
59
+
60
+ # Build a true reference binary that uses inflateBack9 (infback9.c)
61
+ test/payload_decompress_ref_debug: $(PD_REF_OBJS)
62
+ mkdir -p test
63
+ $(CC) $(DEBUG_DEFINES) $(DEBUG_CFLAGS) $(PD_REF_OBJS) -o $@
64
+
65
+ # Build nowindow debug variant
66
+ test/payload_decompress_nowindow_debug: $(PD_NOWINDOW_DEBUG_OBJS)
67
+ mkdir -p test
68
+ $(CC) $(DEBUG_DEFINES) $(DEBUG_CFLAGS) $(PD_NOWINDOW_DEBUG_OBJS) -o $@
69
+
70
+ test/payload_decompress_ref: $(PD_REF_OBJS_RELEASE)
71
+ mkdir -p test
72
+ $(CC) $(CFLAGS) $(PD_REF_OBJS_RELEASE) -o $@
73
+
74
+ # pattern rules to compile sources into build object dirs
75
+ build/%.o: %.c
76
+ @echo "CC $< -> $@"
77
+ @mkdir -p $(dir $@)
78
+ $(CC) $(CFLAGS) -c $< -o $@
79
+
80
+ build/debug/%.o: %.c
81
+ @echo "CC (debug) $< -> $@"
82
+ @mkdir -p $(dir $@)
83
+ $(CC) $(DEBUG_DEFINES) $(DEBUG_CFLAGS) -c $< -o $@
84
+
85
+ run_ref_test:
86
+ @mkdir -p tmp
87
+ @sh -c '\
88
+ ./test/payload_decompress_ref_debug ./test/ref-data/10k_lines.deflate64 tmp/out_ref.bin 2> tmp/trace_ref.log; \
89
+ rc=$$?; \
90
+ if [ $$rc -eq 0 ] && [ -s tmp/out_ref.bin ]; then \
91
+ echo OK >> tmp/trace_ref.log; \
92
+ else \
93
+ echo KO >> tmp/trace_ref.log; \
94
+ fi'
95
+
96
+ .PHONY: test_all ref_test run_ref_test
97
+
98
+ .PHONY: run_all_payloads_verify_ci
99
+ run_all_payloads_verify_ci:
100
+ @echo "Building quiet debug harnesses (no INF9_TRACE) and running full verification..."
101
+ @$(MAKE) DEBUG_DEFINES= test/payload_decompress_test_debug test/payload_decompress_ref_debug test/payload_decompress_nowindow_debug >/dev/null 2>&1 || true
102
+ @mkdir -p tmp/all_runs
103
+ @./test/run_all_payloads_and_verify.sh | tee tmp/all_runs/run_all_verify.log
104
+ @echo "wrote tmp/all_runs/run_all_verify.log"
105
+
106
+ .PHONY: ci
107
+
108
+ ci:
109
+ @mkdir -p tmp
110
+ @echo "CI START: $$(date)" > tmp/ci_run.log
111
+ @echo "Running make test (build)" >> tmp/ci_run.log
112
+ @$(MAKE) test_all >> tmp/ci_run.log 2>&1 || true
113
+ @for target run_ref_test; do \
114
+ echo "=== $$target ===" >> tmp/ci_run.log; \
115
+ $(MAKE) $$target >> tmp/ci_run.log 2>&1 || true; \
116
+ done
117
+ @echo "CI DONE: $$(date)" >> tmp/ci_run.log
118
+ @echo "Summary generated at $$(date)" > tmp/ci_summary.txt
119
+ @for out in tmp/out_*.bin; do [ -f "$$out" ] && stat -f"%N %z" "$$out" >> tmp/ci_summary.txt || true; done
120
+ @echo "" >> tmp/ci_summary.txt
121
+ @echo "-- last 10 lines of traces --" >> tmp/ci_summary.txt
122
+ @for trace in tmp/trace_*.log; do echo "--- $$trace ---" >> tmp/ci_summary.txt; tail -n 10 "$$trace" >> tmp/ci_summary.txt 2>/dev/null || true; echo "" >> tmp/ci_summary.txt; done
123
+
124
+ # Include generated dependency files (if present)
125
+ -include $(PD_OBJS:.o=.d) $(PD_DEBUG_OBJS:.o=.d)
126
+
127
+ # -----------------------------------------------------------------------------
128
+ # WASM build target (convenience target to produce dist/zlib-streams-dev.wasm)
129
+ # -----------------------------------------------------------------------------
130
+ EMCC ?= emsdk/upstream/emscripten/emcc
131
+
132
+ WASM_SRCS = src/wasm/inflate9_stream_wasm.c src/wasm/inflate_stream_wasm.c src/wasm/deflate_stream_wasm.c src/inflate9.c \
133
+ src/zlib/contrib/infback9/inftree9.c \
134
+ src/zlib/inffast.c src/zlib/inflate.c src/zlib/inftrees.c src/zlib/zutil.c \
135
+ src/zlib/crc32.c src/zlib/adler32.c src/zlib/trees.c src/zlib/deflate.c
136
+ WASM_CFLAGS = -Isrc -Isrc/zlib -Isrc/zlib/contrib/infback9 -O2 -flto -DDYNAMIC_CRC_TABLE
137
+
138
+ .PHONY: wasm
139
+ wasm: dist/zlib-streams-dev.wasm
140
+
141
+ .PHONY: wasm_traced
142
+ wasm_traced: dist/zlib-streams_traced.wasm
143
+
144
+ dist/zlib-streams_traced.wasm: $(WASM_SRCS)
145
+ @echo "Building traced $@ using $(EMCC)"
146
+ @mkdir -p dist
147
+ $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) $(DEBUG_DEFINES_TRACED) -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
148
+ -s EXPORTED_FUNCTIONS='["_inflate9_new","_inflate9_init","_inflate9_init_raw","_inflate9_process","_inflate9_end","_inflate9_last_consumed","_inflate_new","_inflate_init","_inflate_init_raw","_inflate_init_gzip","_inflate_process","_inflate_end","_inflate_last_consumed","_deflate_new","_deflate_init","_deflate_init_raw","_deflate_init_gzip","_deflate_process","_deflate_end","_deflate_last_consumed","_malloc","_free"]' \
149
+ -o $@
150
+
151
+ # Run reference C and WASM test suites over payloads in test/ref-data
152
+ .PHONY: run_ref_c_tests
153
+ run_ref_c_tests: test/payload_decompress_test_debug test/payload_decompress_ref_debug test/payload_decompress_nowindow_debug
154
+ @echo "Running C reference harnesses over deflate64 payloads"
155
+ @mkdir -p tmp/all_runs
156
+ @./test/run_deflate64_suite.sh
157
+
158
+ .PHONY: run_ref_wasm_tests
159
+ run_ref_wasm_tests: dist/zlib-streams-dev.wasm
160
+ @echo "Running WASM runner over deflate64 payloads (sequential by default)"
161
+ @mkdir -p tmp/all_runs
162
+ @$(MAKE) run_ref_wasm_seq
163
+ @$(MAKE) run_wasm_roundtrip_mem
164
+
165
+ .PHONY: run_ref_wasm_seq
166
+ run_ref_wasm_seq: dist/zlib-streams-dev.wasm
167
+ @echo "Running WASM runner sequentially per payload (safe, non-blocking)"
168
+ @mkdir -p tmp/all_runs
169
+ @sh -c '\
170
+ for p in test/ref-data/*deflate64*; do \
171
+ [ -f "$$p" ] || continue; \
172
+ f=$$(basename "$$p"); \
173
+ printf "\nPayload: %s\n" "$$f"; \
174
+ rm -f tmp/all_runs/wasm__$$f.out; \
175
+ node src/wasm/tests/test_inflate9_stream.js dist/zlib-streams-dev.wasm "$$p" tmp/all_runs/wasm__$$f.out || printf " NODE_RC:%s for %s\n" "$$?" "$$f"; \
176
+ if [ -f tmp/all_runs/wasm__$$f.out ]; then \
177
+ printf " wrote tmp/all_runs/wasm__%s.out (size=%s)\n" "$$f" "$(stat -f%z tmp/all_runs/wasm__$$f.out 2>/dev/null || echo unknown)"; \
178
+ ref=tmp/all_runs/payload_decompress_ref_debug__$$f.out; \
179
+ if [ -f "$$ref" ]; then \
180
+ h1=`shasum -a 256 tmp/all_runs/wasm__$$f.out | cut -d\ -f1`; \
181
+ h2=`shasum -a 256 "$$ref" | cut -d\ -f1`; \
182
+ if [ "$$h1" = "$$h2" ]; then \
183
+ printf " SHA256 MATCH: %s\n" "$$h1"; \
184
+ else \
185
+ printf " SHA256 MISMATCH: wasm=%s ref=%s\n" "$$h1" "$$h2"; \
186
+ fi; \
187
+ else \
188
+ printf " ref missing: %s\n" "$$ref"; \
189
+ fi; \
190
+ fi; \
191
+ done'
192
+
193
+ .PHONY: run_ref_tests
194
+ run_ref_tests: run_ref_c_tests run_ref_wasm_tests
195
+ @echo "Completed C+WASM reference test suites"
196
+
197
+ .PHONY: run_wasm_roundtrip
198
+ run_wasm_roundtrip: dist/zlib-streams-dev.wasm
199
+ @echo "Running wasm roundtrip tests over tmp/all_runs/roundtrip_input*"
200
+ @mkdir -p tmp/all_runs
201
+ # populate tmp/all_runs with canonical roundtrip inputs
202
+ @cp -f test/ref-data/roundtrip_inputs/roundtrip_input.txt tmp/all_runs/roundtrip_input.txt
203
+ @cp -f test/ref-data/roundtrip_inputs/roundtrip_input1.txt tmp/all_runs/roundtrip_input1.txt
204
+ @cp -f test/ref-data/roundtrip_inputs/roundtrip_input3.bin tmp/all_runs/roundtrip_input3.bin
205
+ @sh -c '\
206
+ for p in tmp/all_runs/roundtrip_input*; do \
207
+ [ -f "$$p" ] || continue; \
208
+ f=$$(basename "$$p"); \
209
+ printf "\nInput: %s\n" "$$f"; \
210
+ rm -f tmp/all_runs/roundtrip_out__$$f; \
211
+ node src/wasm/tests/test_round_trip_stream.js dist/zlib-streams-dev.wasm "$$p" tmp/all_runs/roundtrip_out__$$f 2>&1 | sed -n '1,200p'; \
212
+ rc=$$?; \
213
+ if [ $$rc -eq 0 ]; then \
214
+ printf " OK: %s\n" "$$f"; \
215
+ else \
216
+ printf " FAIL (rc=%s): %s\n" "$$rc" "$$f"; \
217
+ fi; \
218
+ done'
219
+
220
+ .PHONY: run_wasm_roundtrip_mem
221
+ run_wasm_roundtrip_mem: dist/zlib-streams-dev.wasm
222
+ @echo "Running wasm roundtrip (in-memory) tests over tmp/all_runs/roundtrip_input*"
223
+ @mkdir -p tmp/all_runs
224
+ @sh -c '\
225
+ for p in tmp/all_runs/roundtrip_input*; do \
226
+ [ -f "$$p" ] || continue; \
227
+ f=$$(basename "$$p"); \
228
+ printf "\nInput: %s\n" "$$f"; \
229
+ node src/wasm/tests/test_round_trip_stream_mem.js dist/zlib-streams-dev.wasm "$$p" 2>&1 | sed -n "1,200p"; \
230
+ rc=$$?; \
231
+ if [ $$rc -eq 0 ]; then \
232
+ printf " OK: %s\n" "$$f"; \
233
+ else \
234
+ printf " FAIL (rc=%s): %s\n" "$$rc" "$$f"; \
235
+ fi; \
236
+ done'
237
+
238
+ .PHONY: run_transform_roundtrip
239
+ run_transform_roundtrip: dist/zlib-streams-dev.wasm
240
+ @echo "Running TransformStream roundtrip test"
241
+ @node src/wasm/tests/test_transform_roundtrip.js dist/zlib-streams-dev.wasm
242
+
243
+ .PHONY: deno_run_tests
244
+ deno_run_tests:
245
+ @echo "Running Deno test suite (deno/run_all_tests.sh)"
246
+ @chmod +x deno/run_all_tests.sh || true
247
+ @./deno/run_all_tests.sh dist/zlib-streams.wasm
248
+
249
+ .PHONY: run_inflate9_roundtrip_all
250
+ run_inflate9_roundtrip_all: dist/zlib-streams-dev.wasm
251
+ @echo "Running inflate9 roundtrip over deflate64 payloads"
252
+ @node src/wasm/tests/test_inflate9_roundtrip_all.js dist/zlib-streams-dev.wasm
253
+
254
+ .PHONY: test_decompressionstream_inflate9
255
+ test_decompressionstream_inflate9: dist/zlib-streams-dev.wasm
256
+ @echo "Testing DecompressionStreamZlib against native inflate9 for deflate64 payloads"
257
+ @node src/wasm/tests/test_decompressionstream_inflate9.js dist/zlib-streams-dev.wasm
258
+
259
+
260
+ # Single target to run the main wasm/TransformStream tests used during development
261
+ .PHONY: run_all_tests
262
+ run_all_tests: dist/zlib-streams-dev.wasm
263
+ @echo "Running all wasm TransformStream tests"
264
+ @$(MAKE) run_ref_wasm_tests
265
+ @$(MAKE) run_wasm_roundtrip
266
+ # Additional roundtrip tests not covered by the generic runners
267
+ @node src/wasm/tests/test_round_trip_stream_deflate.js dist/zlib-streams-dev.wasm
268
+ @node src/wasm/tests/test_round_trip_stream_gzip.js dist/zlib-streams-dev.wasm
269
+ @mkdir -p tmp/all_runs
270
+ # Ensure a raw-deflate test input exists (create from a repeated pattern)
271
+ @node -e "const fs=require('fs'), z=require('zlib'); fs.writeFileSync('tmp/all_runs/roundtrip_input3.bin', z.deflateRawSync(Buffer.alloc(24000, 'x')));"
272
+ @node src/wasm/tests/test_inflate_stream.js dist/zlib-streams-dev.wasm tmp/all_runs/roundtrip_input3.bin tmp/all_runs/inflate_stream_out.bin
273
+ # CLI helper run (small sample) for regressions/throughput checks
274
+ @node src/wasm/tests/run_roundtrip_cli.js deflate 24000 dist/zlib-streams-dev.wasm
275
+ @$(MAKE) run_transform_roundtrip
276
+ @$(MAKE) test_decompressionstream_inflate9
277
+ @echo "Completed run_all_tests"
278
+
279
+ dist/zlib-streams-dev.wasm: $(WASM_SRCS)
280
+ @echo "Building $@ using $(EMCC)"
281
+ @mkdir -p dist
282
+ $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
283
+ -s EXPORTED_FUNCTIONS='["_inflate9_new","_inflate9_init","_inflate9_init_raw","_inflate9_process","_inflate9_end","_inflate9_last_consumed","_inflate_new","_inflate_init","_inflate_init_raw","_inflate_init_gzip","_inflate_process","_inflate_end","_inflate_last_consumed","_deflate_new","_deflate_init","_deflate_init_raw","_deflate_init_gzip","_deflate_process","_deflate_end","_deflate_last_consumed","_malloc","_free"]' \
284
+ -o $@
285
+ cp src/wasm/api/zlib-streams.js dist/zlib-streams.js
286
+
287
+ # Production-optimized wasm: smaller build with -Oz and no extra runtime methods.
288
+ .PHONY: wasm_prod
289
+ wasm_prod: dist/zlib-streams.wasm
290
+
291
+ dist/zlib-streams.wasm: $(WASM_SRCS)
292
+ @echo "Building production wasm $@ using $(EMCC)"
293
+ @mkdir -p dist
294
+ $(EMCC) $(WASM_SRCS) $(WASM_CFLAGS) -Oz -flto -s WASM=1 -s STANDALONE_WASM=1 --no-entry \
295
+ -s FILESYSTEM=0 -s DISABLE_EXCEPTION_CATCHING=1 \
296
+ -s EXPORTED_FUNCTIONS='["_inflate9_new","_inflate9_init","_inflate9_init_raw","_inflate9_process","_inflate9_end","_inflate9_last_consumed","_inflate_new","_inflate_init","_inflate_init_raw","_inflate_init_gzip","_inflate_process","_inflate_end","_inflate_last_consumed","_deflate_new","_deflate_init","_deflate_init_raw","_deflate_init_gzip","_deflate_process","_deflate_end","_deflate_last_consumed","_malloc","_free"]' \
297
+ -o $@
298
+ cp src/wasm/api/zlib-streams.js dist/zlib-streams.js
299
+ @which wasm-opt >/dev/null 2>&1 && { echo "Running wasm-opt -Oz --enable-bulk-memory-opt"; wasm-opt -Oz --enable-bulk-memory-opt -o $@ $@ || true; } || true
300
+
301
+ # -----------------------------------------------------------------------------
302
+ # Optional generator: build a C++ tool that creates Deflate64 ZIPs using the
303
+ # 7-Zip SDK. This target is guarded: it only compiles when the SDK is present
304
+ # at src/7zip. The generator is not built by default.
305
+ # -----------------------------------------------------------------------------
306
+ CXX ?= g++
307
+ CXXFLAGS = -std=c++17 -I./src -I./src/7zip -O2
308
+
309
+ SDK_ROOT = src/7zip/CPP/7zip
310
+ # Guard building the SDK-backed generator. Set ENABLE_SDK_GENERATOR=1 to
311
+ # attempt compilation. By default, we skip to avoid platform-specific SDK
312
+ # build errors on non-Windows hosts.
313
+ ENABLE_SDK_GENERATOR ?= 0
314
+
315
+ # Only require the heavy SDK archive when we actually plan to build the
316
+ # SDK-backed generator. This avoids building the SDK object archive when
317
+ # the generator is being built in CLI-only mode.
318
+ SDK_PREREQS := $(if $(filter 1,$(ENABLE_SDK_GENERATOR)),build/lib7zip.a,)
319
+
320
+ # Minimal curated list of SDK sources required to build a Zip creator that
321
+ # uses compress/deflate/deflate64. This avoids compiling UI/Explorer/Windows
322
+ # specific code which fails on non-Windows hosts. Add more files here if
323
+ # the linker reports missing symbols.
324
+ SDK_FAST_SRCS = \
325
+ $(SDK_ROOT)/Archive/Zip/ZipAddCommon.cpp \
326
+ $(SDK_ROOT)/Archive/Zip/ZipHandler.cpp \
327
+ $(SDK_ROOT)/Archive/Zip/ZipHandlerOut.cpp \
328
+ $(SDK_ROOT)/Archive/Zip/ZipIn.cpp \
329
+ $(SDK_ROOT)/Archive/Zip/ZipItem.cpp \
330
+ $(SDK_ROOT)/Archive/Zip/ZipOut.cpp \
331
+ $(SDK_ROOT)/Archive/Zip/ZipRegister.cpp \
332
+ $(SDK_ROOT)/Archive/Zip/ZipUpdate.cpp \
333
+ $(SDK_ROOT)/Common/CreateCoder.cpp \
334
+ $(SDK_ROOT)/../Common/MyString.cpp \
335
+ $(SDK_ROOT)/../Common/StringConvert.cpp \
336
+ $(SDK_ROOT)/../Common/UTFConvert.cpp \
337
+ $(SDK_ROOT)/../Common/IntToString.cpp \
338
+ $(SDK_ROOT)/../Common/MyWindows.cpp \
339
+ $(SDK_ROOT)/Common/StreamObjects.cpp \
340
+ $(SDK_ROOT)/Common/OutMemStream.cpp \
341
+ $(SDK_ROOT)/Common/OutBuffer.cpp \
342
+ $(SDK_ROOT)/Common/InBuffer.cpp \
343
+ $(SDK_ROOT)/Common/InOutTempBuffer.cpp \
344
+ $(SDK_ROOT)/Common/StreamUtils.cpp \
345
+ $(SDK_ROOT)/Common/OffsetStream.cpp \
346
+ $(SDK_ROOT)/Common/FileStreams.cpp \
347
+ $(SDK_ROOT)/Common/CWrappers.cpp \
348
+ $(SDK_ROOT)/Common/FilterCoder.cpp \
349
+ $(SDK_ROOT)/Compress/CopyCoder.cpp \
350
+ $(SDK_ROOT)/Compress/DeflateRegister.cpp \
351
+ $(SDK_ROOT)/Compress/DeflateEncoder.cpp \
352
+ $(SDK_ROOT)/Compress/DeflateDecoder.cpp \
353
+ $(SDK_ROOT)/Compress/LzOutWindow.cpp \
354
+ $(SDK_ROOT)/Compress/Deflate64Register.cpp \
355
+ $(SDK_ROOT)/../Windows/FileIO.cpp \
356
+ $(SDK_ROOT)/../Windows/FileFind.cpp \
357
+ $(SDK_ROOT)/../Windows/FileName.cpp \
358
+ $(SDK_ROOT)/../Windows/FileMapping.cpp \
359
+ $(SDK_ROOT)/../Windows/System.cpp \
360
+ $(SDK_ROOT)/../Windows/TimeUtils.cpp \
361
+ $(SDK_ROOT)/../Windows/PropVariant.cpp \
362
+ $(SDK_ROOT)/../Windows/PropVariantConv.cpp \
363
+ $(SDK_ROOT)/../Windows/MemoryGlobal.cpp \
364
+ $(SDK_ROOT)/../Windows/MemoryLock.cpp \
365
+ $(SDK_ROOT)/../Windows/SystemInfo.cpp
366
+
367
+ SDK_C_SRCS := $(wildcard src/7zip/C/*.c)
368
+
369
+ SDK_C_OBJS := $(patsubst src/7zip/C/%.c,build/7zip/C/%.o,$(SDK_C_SRCS))
370
+
371
+ SDK_CPP := $(shell [ -d src/7zip ] && [ "$(ENABLE_SDK_GENERATOR)" -eq "1" ] && echo $(SDK_FAST_SRCS) || echo)
372
+ SDK_OBJS := $(patsubst $(SDK_ROOT)/%.cpp,build/7zip/%.o,$(SDK_CPP))
373
+
374
+ # Any extra non-SDK .cpp sources that should be compiled into the SDK archive
375
+ SDK_EXTRA_SRCS := src/generator/sdk_deflate64.cpp \
376
+ src/generator/win_compat.cpp \
377
+ src/generator/com_shims.cpp \
378
+ src/generator/sdk_shims.cpp
379
+ SDK_EXTRA_OBJS := $(patsubst src/%.cpp,build/7zip/%.o,$(SDK_EXTRA_SRCS))
380
+
381
+ build/lib7zip.a: $(SDK_OBJS) $(SDK_C_OBJS) $(SDK_EXTRA_OBJS)
382
+ @echo "Archiving SDK objects -> $@"
383
+ @mkdir -p $(dir $@)
384
+ @ar rcs $@ $(SDK_OBJS) $(SDK_C_OBJS) $(SDK_EXTRA_OBJS)
385
+
386
+ # Rule to build SDK sources (in-tree)
387
+ build/7zip/%.o: $(SDK_ROOT)/%.cpp
388
+ @echo "CXX sdk $< -> $@"
389
+ @mkdir -p $(dir $@)
390
+ $(CXX) $(CXXFLAGS) -I./src/7zip/CPP -I./src/7zip/CPP/7zip -I./src/generator -include src/generator/compat_prefix.h -c $< -o $@
391
+
392
+ # Rule to build extra local cpp sources into the SDK object tree
393
+ build/7zip/%.o: %.cpp
394
+ @echo "CXX local $< -> $@"
395
+ @mkdir -p $(dir $@)
396
+ $(CXX) $(CXXFLAGS) -I./src/7zip/CPP -I./src/7zip/CPP/7zip -c $< -o $@
397
+
398
+ # Rule to build C sources from src/7zip/C into the SDK object tree
399
+ build/7zip/C/%.o: $(SDK_ROOT)/../../C/%.c
400
+ @echo "CC sdk C $< -> $@"
401
+ @mkdir -p $(dir $@)
402
+ $(CC) $(CFLAGS) -I./src/7zip/C -I./src/7zip/CPP -I./src/7zip/CPP/7zip -c $< -o $@
403
+
404
+ # specific rule for sources under src/generator
405
+ build/7zip/generator/%.o: src/generator/%.cpp
406
+ @echo "CXX gen $< -> $@"
407
+ @mkdir -p $(dir $@)
408
+ $(CXX) $(CXXFLAGS) -I./src/7zip/CPP -I./src/7zip/CPP/7zip -c $< -o $@
409
+
410
+ generator: $(SDK_PREREQS)
411
+ @if [ "$(ENABLE_SDK_GENERATOR)" -ne "1" ]; then \
412
+ mkdir -p bin; \
413
+ echo "Building CLI-only generator (requires '7z' in PATH)"; \
414
+ $(CXX) $(CXXFLAGS) -o bin/create_deflate64 src/generator/create_deflate64.cpp || (echo "generator build failed"; exit 1); \
415
+ echo "built bin/create_deflate64"; \
416
+ else \
417
+ if [ -d src/7zip ]; then \
418
+ mkdir -p bin; \
419
+ echo "Building SDK-backed generator and linking with SDK library"; \
420
+ $(CXX) $(CXXFLAGS) -DUSE_7ZIP_SDK -I./src/7zip/CPP -I./src/7zip/CPP/7zip -o bin/create_deflate64 src/generator/create_deflate64.cpp build/7zip/Compress/Deflate64Register.o build/lib7zip.a || (echo "generator build failed"; exit 1); \
421
+ echo "built bin/create_deflate64"; \
422
+ else \
423
+ echo "skipping generator build: src/7zip not present (run 'make src/7zip' to fetch)"; \
424
+ fi; \
425
+ fi
426
+
427
+ # Helper: download and extract 7-Zip SDK into src/7zip
428
+ .PHONY: src/7zip
429
+ src/7zip:
430
+ @echo "Downloading 7-Zip LZMA SDK and extracting into src/7zip";
431
+ @mkdir -p tmp
432
+ @test -f tmp/lzma2501.7z || curl -sSL -o tmp/lzma2501.7z https://7-zip.org/a/lzma2501.7z
433
+ @mkdir -p src
434
+ @rm -rf src/7zip
435
+ @echo "Extracting tmp/lzma2501.7z -> src/7zip";
436
+ @mkdir -p src/7zip
437
+ @command -v 7z >/dev/null 2>&1 || (echo "7z not found: install p7zip to extract the SDK or extract tmp/lzma2501.7z manually"; exit 1)
438
+ @7z x -y -otmp tmp/lzma2501.7z >/dev/null 2>&1 || (echo "failed to extract SDK with 7z"; exit 1)
439
+ @# The archive contains a 7zip folder; move it to src/7zip/CPP
440
+ @if [ -d tmp/CPP ]; then mv tmp/CPP src/7zip/CPP; elif [ -d tmp/7z ]; then mv tmp/7z src/7zip/CPP; else mv tmp/* src/7zip/CPP 2>/dev/null || true; fi
441
+ @echo "SDK extracted to src/7zip/CPP"
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # zlib-streams Project: WASM-based Compression Streams API implementation using zlib, with support for deflate64 decompression
2
+
3
+ The zlib source code is included as a submodule in `src/zlib`.
4
+
5
+ ## Directory Structure
6
+
7
+ - `src/` — C source code, including inflate9, zlib, wasm bindings
8
+ - `dist/` — WASM build outputs
9
+ - `test/` — C test harnesses, payloads, and shell scripts for verification
10
+ - `deno/` — Deno/Node.js test scripts and WASM runners
11
+
12
+ ## Getting Started
13
+
14
+ ### 1. Clone the repository and initialize submodules
15
+ ```sh
16
+ git clone https://github.com/gildas-lormeau/zlib-streams.git
17
+ cd zlib-streams
18
+ git submodule update --init --recursive
19
+ ```
20
+
21
+ ### 2. Build WASM module
22
+ - Developmeent
23
+ ```sh
24
+ make wasm
25
+ ```
26
+ Output: `dist/zlib-streams-dev.wasm` and `dist/zlib-streams.js`
27
+
28
+ - Production
29
+ ```sh
30
+ make wasm_prod
31
+ ```
32
+ Output: `dist/zlib-streams.wasm` and `dist/zlib-streams.js`
33
+
34
+ ## License
35
+ See LICENSE for details.
@@ -0,0 +1,157 @@
1
+ /* eslint-disable no-unused-vars */
2
+ /* global Buffer, process, TransformStream */
3
+
4
+ let wasm, malloc, free, memory;
5
+
6
+ export function setWasmExports(wasmAPI) {
7
+ wasm = wasmAPI;
8
+ ({ malloc, free, memory } = wasm);
9
+ }
10
+
11
+ function _make(isCompress, type, options = {}) {
12
+ const level = (typeof options.level === "number") ? options.level : -1;
13
+ const outBufferSize = (typeof options.outBuffer === "number") ? options.outBuffer : 64 * 1024;
14
+ const inBufferSize = (typeof options.inBufferSize === "number") ? options.inBufferSize : 64 * 1024;
15
+
16
+ return new TransformStream({
17
+ start() {
18
+ let result;
19
+ this.out = malloc(outBufferSize);
20
+ this.in = malloc(inBufferSize);
21
+ this.inBufferSize = inBufferSize;
22
+ this._scratch = new Uint8Array(outBufferSize);
23
+ if (isCompress) {
24
+ this._process = wasm.deflate_process;
25
+ this._last_consumed = wasm.deflate_last_consumed;
26
+ this._end = wasm.deflate_end;
27
+ this.streamHandle = wasm.deflate_new();
28
+ if (type === "gzip") {
29
+ result = wasm.deflate_init_gzip(this.streamHandle, level);
30
+ } else if (type === "deflate-raw") {
31
+ result = wasm.deflate_init_raw(this.streamHandle, level);
32
+ } else {
33
+ result = wasm.deflate_init(this.streamHandle, level);
34
+ }
35
+ } else {
36
+ if (type === "deflate64-raw") {
37
+ this._process = wasm.inflate9_process;
38
+ this._last_consumed = wasm.inflate9_last_consumed;
39
+ this._end = wasm.inflate9_end;
40
+ this.streamHandle = wasm.inflate9_new();
41
+ result = wasm.inflate9_init_raw(this.streamHandle);
42
+ } else {
43
+ this._process = wasm.inflate_process;
44
+ this._last_consumed = wasm.inflate_last_consumed;
45
+ this._end = wasm.inflate_end;
46
+ this.streamHandle = wasm.inflate_new();
47
+ if (type === "deflate-raw") {
48
+ result = wasm.inflate_init_raw(this.streamHandle);
49
+ } else if (type === "gzip") {
50
+ result = wasm.inflate_init_gzip(this.streamHandle);
51
+ } else {
52
+ result = wasm.inflate_init(this.streamHandle);
53
+ }
54
+ }
55
+ }
56
+ if (result !== 0) {
57
+ throw new Error("init failed:" + result);
58
+ }
59
+ },
60
+ transform(chunk, controller) {
61
+ try {
62
+ const buffer = chunk;
63
+ const heap = new Uint8Array(memory.buffer);
64
+ const process = this._process;
65
+ const last_consumed = this._last_consumed;
66
+ const out = this.out;
67
+ const scratch = this._scratch;
68
+ let offset = 0;
69
+ while (offset < buffer.length) {
70
+ const toRead = Math.min(buffer.length - offset, 32 * 1024);
71
+ if (!this.in || this.inBufferSize < toRead) {
72
+ if (this.in && free) {
73
+ free(this.in);
74
+ }
75
+ this.in = malloc(toRead);
76
+ this.inBufferSize = toRead;
77
+ }
78
+ heap.set(buffer.subarray(offset, offset + toRead), this.in);
79
+ const result = process(this.streamHandle, this.in, toRead, out, outBufferSize, 0);
80
+ if (!isCompress && result < 0) {
81
+ throw new Error("process error:" + result);
82
+ }
83
+ const prod = result & 0x00ffffff;
84
+ if (prod) {
85
+ scratch.set(heap.subarray(out, out + prod), 0);
86
+ controller.enqueue(scratch.slice(0, prod));
87
+ }
88
+ const consumed = last_consumed(this.streamHandle);
89
+ if (consumed === 0) {
90
+ break;
91
+ }
92
+ offset += consumed;
93
+ }
94
+ } catch (error) {
95
+ if (this._end && this.streamHandle) {
96
+ this._end(this.streamHandle);
97
+ }
98
+ if (this.in && free) {
99
+ free(this.in);
100
+ }
101
+ if (this.out && free) {
102
+ free(this.out);
103
+ }
104
+ controller.error(error);
105
+ }
106
+ },
107
+ flush(controller) {
108
+ try {
109
+ const heap = new Uint8Array(memory.buffer);
110
+ const process = this._process;
111
+ const out = this.out;
112
+ const scratch = this._scratch;
113
+ while (true) {
114
+ const result = process(this.streamHandle, 0, 0, out, outBufferSize, 4);
115
+ if (!isCompress && result < 0) {
116
+ throw new Error("process error:" + result);
117
+ }
118
+ const produced = result & 0x00ffffff;
119
+ const code = (result >> 24) & 0xff;
120
+ if (produced) {
121
+ scratch.set(heap.subarray(out, out + produced), 0);
122
+ controller.enqueue(scratch.slice(0, produced));
123
+ }
124
+ if (code === 1 || produced === 0) {
125
+ break;
126
+ }
127
+ }
128
+ } catch (error) {
129
+ controller.error(error);
130
+ } finally {
131
+ if (this._end && this.streamHandle) {
132
+ const result = this._end(this.streamHandle);
133
+ if (result !== 0) {
134
+ controller.error(new Error("end error:" + result));
135
+ }
136
+ }
137
+ if (this.in && free) {
138
+ free(this.in);
139
+ }
140
+ if (this.out && free) {
141
+ free(this.out);
142
+ }
143
+ }
144
+ }
145
+ });
146
+ }
147
+
148
+ export class CompressionStreamZlib {
149
+ constructor(type = "deflate", options) {
150
+ return _make(true, type, options);
151
+ }
152
+ }
153
+ export class DecompressionStreamZlib {
154
+ constructor(type = "deflate", options) {
155
+ return _make(false, type, options);
156
+ }
157
+ }
Binary file